GetDIBits zwraca "czarną" tablicę

Odpowiedz Nowy wątek
2012-10-28 12:21
0

Mam kodzik:

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

using namespace std;

int main()
{
    static BITMAPINFO bh;
    unsigned char* bits = new unsigned char[1080*1920*3];

    HDC hdc = GetDC(HWND_DESKTOP);
    HBITMAP hbm = CreateCompatibleBitmap( hdc, 1920, 1080);

    bh.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bh.bmiHeader.biWidth  = 1920;
    bh.bmiHeader.biHeight = 1080;
    bh.bmiHeader.biPlanes = 1;
    bh.bmiHeader.biBitCount = 24;
    bh.bmiHeader.biCompression = BI_RGB;
    bh.bmiHeader.biSizeImage = 0;

    GetDIBits(hdc,hbm,0,1080,bits,(BITMAPINFO*)&bh,DIB_RGB_COLORS);

    FILE *f = fopen("C:\dump.raw", "wb");
    fwrite(bits, 1, 1920*1080*3, f);
    fclose(f);
    return 0;
}

Który powinien raczej działać, ale do pliku mi zwraca całą czarną tablicę (obraz jest cał czarny). Jakieś pomysły? Szukam i szukam, pytałem paru osób, ale nie wiem o co może chodzić :(


Programuję w: C#, C++, PHP, AutoIT, Python, Java
GG: 3027377

Pozostało 580 znaków

2012-10-28 13:19
0
  1. Dlaczego zakładasz, że głębia koloru w planie takim jaki ma ekran nie może przekroczyć 24-bit? Dzisiaj standardem jest 32-bit, a takie coś Ci się nie zmieści jeżeli arbitralnie dasz za mało miejsca.
  2. Skoro dajesz systemowi wolną rękę jakiego planu użyje, to czemu próbujesz arbitralnie wypełniać BITMAPINFO danymi wyssanymi z palca?

Jeżeli ktoś komuś coś, ewentualnie nikt nikomu nic, to właściwie po co...?
GetDIBits konwertuje bitmapę na format, który chce otrzymać użytkownik. - Rev 2012-10-28 13:27
Nie wiem czemu to wywołanie przeleciało mi przed oczami niezauważone. Muszę się zapakować do okulisty z wizytą... - Olamagato 2012-10-29 11:04

Pozostało 580 znaków

2012-10-28 13:25
Rev
1

Tworzysz uchwyt do bitmapy, której tak naprawdę nigdzie nie ma. Każda bitmapa musi mieć jakiś kontekst, musi być przypisana do jakiegoś urządzenia.
Stwórz kompatybilne memory device (CreateCompatibleDC), przypisz kompatybilną bitmapę do tego urządzenia (SelectObject), skopiuj tam zawartość ekranu (BitBlt) i dopiero z niej pobierz piksele (GetDIBits). Zwolnij bitmapę (DeleteObject) i urządzenie (DeleteDC).


Pozostało 580 znaków

2012-10-28 14:25
0

Spróbowałem coś takiego, ale nadal nic:

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

using namespace std;

int main()
{
    static BITMAPINFO bh;
    unsigned char* bits = new unsigned char[1080*1920*3];

    HDC hdc = GetDC(HWND_DESKTOP);
    HDC hdcc = CreateCompatibleDC(hdc);
    HBITMAP hbm = CreateCompatibleBitmap( hdc, 1920, 1080);
    SelectObject(hdcc, hbm);
    BitBlt(hdc, 0, 0, 1920, 1080, hdcc, 0, 0, SRCCOPY);

    bh.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bh.bmiHeader.biWidth  = 1920;
    bh.bmiHeader.biHeight = 1080;
    bh.bmiHeader.biPlanes = 1;
    bh.bmiHeader.biBitCount = 24;
    bh.bmiHeader.biCompression = BI_RGB;
    bh.bmiHeader.biSizeImage = 0;

    GetDIBits(hdc,hbm,0,1080,bits,(BITMAPINFO*)&bh,DIB_RGB_COLORS);

    DeleteObject(hbm);
    ReleaseDC(hdc);
    DeleteDC(hdcc);

    FILE *f = fopen("C:\dump.raw", "wb");
    fwrite(bits, 1, 1920*1080*3, f);
    fclose(f);
    return 0;
}

Programuję w: C#, C++, PHP, AutoIT, Python, Java
GG: 3027377
edytowany 2x, ostatnio: Heniut, 2012-10-28 14:28

Pozostało 580 znaków

2012-10-29 00:33
Rev
1

Odwrotnie w BitBlt: najpierw podaje się docelowy kontekst, a później źródłowy.

Ten kod w ogóle się skompilował? ReleaseDC przyjmuje dwa parametry, w tym uchwyt do okna, którego nie masz ;). W ogóle wywołanie tej funkcji nie jest potrzebne.


Pozostało 580 znaków

2012-10-29 16:09
0

Wielkie dzięki! Po zmianie obraz jest taki: http://puu.sh/1k7jh czyli odwrócony i nie w rgb tylko bgr dało by się to jakoś w miarę szybko "zamienić" na rgb i odwrócić (chyba, że to wpisywanie do pliku mi coś miesza)?


Programuję w: C#, C++, PHP, AutoIT, Python, Java
GG: 3027377

Pozostało 580 znaków

2012-10-29 20:03
0

Zmieniłem bh.bmiHeader.biHeight = 1080; na bh.bmiHeader.biHeight = -1080; (liczba przeciwna) i obraz już nie jest odwrócony :) Teraz jeszcze tylko pozostała zamiana na rgb. Jakieś porady?


Programuję w: C#, C++, PHP, AutoIT, Python, Java
GG: 3027377

Pozostało 580 znaków

2012-10-30 01:58
Rev

Jeden problem już rozwiązałeś - domyślnie GetDiBits zwraca bitmapę bottom-up. Żeby zamienić ją na top-down trzeba podać ujemną wartość biHeight. Drugi problem jest już właściwie z samym wyświetlaniem. Nasza bitmapa zapisana jest poprawnie, jako RGB. Jednak bitmapy zapisywane do plików (pliki BMP) mają kolory zapisane odwrotnie, czyli w przypadku bitmapy 24-bitowej: BGR888.

for(int i = 0; i < height; i++)
{
    for(int j = 0; j < width * 3; j += 3)
    {
        const size_t offset = i * width * 3 + j;

        unsigned char red = bits[offset];
        bits[offset] = bits[offset + 2];
        bits[offset + 2] = red;
    }
}

Mało optymalny, ale łatwy do zrozumienia kod. Trzeba natomiast zwrócić uwagę na jedną bardzo ważną rzecz - wiersze zawsze są uzupełniane do wielokrotności 4 bajtów. Tutaj problemu nie ma, bo (1920 * 3) dzieli się przez 4, ale w innych przypadkach trzeba mieć to na uwadze.


edytowany 2x, ostatnio: Rev, 2012-10-30 01:59

Pozostało 580 znaków

2012-10-30 08:44
0

Wielkie dzięki za masakryczną pomoc! :)
Temat uważam za rozwiązany !


Programuję w: C#, C++, PHP, AutoIT, Python, Java
GG: 3027377

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0