2014-02-07 42 views
0

我一直在試圖製作一個SDL程序,它能夠拍攝整個屏幕的屏幕截圖,在這種情況下,顯示整個顯示器屏幕的實時信息。我已經成功地使用GDI函數檢索圖像,但我不知道如何在GetDIBits()函數返回後正確處理緩衝區中的數據輸出。到目前爲止,我的形象已經遠遠超出了預期的產出。我目前嘗試的所有格式的顏色都是混亂的,這些格式是SDL紋理可用的大部分32位和24位像素格式。我的win32代碼也可能有錯誤,我不完全確定,因爲顯示的圖像不正確。處理由GetDIBits()返回的像素緩衝區的正確方法是什麼?

這裏是我得到的截圖:

void WINAPI get_screenshot(app_data * app) 
{ 
    HDC desktop = GetDC(NULL); 
    int width = GetDeviceCaps(desktop, HORZRES); 
    int height = GetDeviceCaps(desktop, VERTRES); 
    HDC desktop_copy = CreateCompatibleDC(0); 

    HGDIOBJ old = NULL; 
    HBITMAP screenshot = CreateCompatibleBitmap(desktop_copy, app->viewport.w, app->viewport.h); 

    BITMAPINFOHEADER screenshot_header = { 0 }; 
    screenshot_header.biSize = sizeof(BITMAPINFOHEADER); 
    screenshot_header.biWidth = app->viewport.w; 
    screenshot_header.biHeight = -app->viewport.h; 
    screenshot_header.biPlanes = 1; 
    screenshot_header.biBitCount = 32; 
    screenshot_header.biCompression = BI_RGB; 


    if (!screenshot) 
    { 
     ReleaseDC(NULL, desktop); 
     DeleteDC(desktop_copy); 
     DeleteObject(screenshot); 
     free_app_data(app); 
     win_error("Creating Bitmap", true); 
    } 

    SetStretchBltMode(desktop_copy, HALFTONE); 
    SetBrushOrgEx(desktop_copy, 0, 0, NULL); 
    old = SelectObject(desktop_copy, screenshot); 

    if (!StretchBlt(desktop_copy, 0, 0, app->viewport.w, app->viewport.h, desktop, 0, 0, width, height, SRCCOPY)) 
    { 
     ReleaseDC(NULL, desktop); 
     DeleteDC(desktop_copy); 
     DeleteObject(screenshot); 
     free_app_data(app); 
     win_error("Stretching Screenshot to Window Size", true); 
    } 

    if (!GetDIBits(desktop_copy, screenshot, 0, app->viewport.h, app->pixels, (BITMAPINFO *)&screenshot_header, DIB_RGB_COLORS)) 
    { 
     ReleaseDC(NULL, desktop); 
     DeleteDC(desktop_copy); 
     DeleteObject(screenshot); 
     free_app_data(app); 
     win_error("Getting Window RGB Values", true); 
    } 

    SelectObject(desktop_copy, old); 

    DeleteObject(screenshot); 
    ReleaseDC(NULL, desktop); 
    DeleteDC(desktop_copy); 

    return; 
} 

我感觸最深的調用我的DLL函數的代碼是自我解釋或者不適合這個職位的關鍵,但我會很樂意提供僞代碼或純win32 API代碼(如有必要)。

創建SDL的質感和緩衝的代碼是:

app->frame = SDL_CreateTexture(
            app->renderer, 
            SDL_PIXELFORMAT_ABGR8888, 
            SDL_TEXTUREACCESS_STREAMING, 
            app->viewport.w, 
            app->viewport.h 
           ); 

    if (!app->frame) 
    { 
     free_app_data(app); 
     SDL_errorexit("Creating texture", 1, TRUE); 
    } 

    app->pixels = (Uint32 *)create_array(NULL, (app->viewport.w * app->viewport.h), sizeof(Uint32), zero_array); 

    if (!app->pixels) 
    { 
     free_app_data(app); 
     std_error("Creating pixel buffer", TRUE); 
    } 

同樣,我用我的DLL函數create_array()在這種情況下,但我認爲你應該能夠告訴它做什麼。

產生的圖像是這樣的:

The image output from my program 隨意添加更好的方法或這樣做的純SDL方法。我試過GetPixel(),並且它返回正確的值。儘管如此,多個呼叫的開銷仍然很高。

+0

看起來像潛在的問題是您創建兼容位圖的位置。應該創建位圖的確切大小,而不是SDL位圖的大小。你永遠不想讓GDI縮小位圖,因爲你會得到像你看到的結果。 – BitBank

+0

爲什麼在嘗試獲取簡單屏幕截圖時使用sdl。只用winapi就可以用最少的代碼完成相同的結果。 –

+0

@BBBank我改變了它,但它沒有完全解決它,只是使圖像稍微好一點。 – Name

回答

0

捕捉和繪圖屏幕表單代碼:

HDC hdcScreen, hdcForm; 

hdcScreen = GetDC(NULL); 
hdcForm = GetWindowDC(hwnd); //hwnd is form handle 

StretchBlt(hdcForm, 0, 0, formW, formH, hdcScreen , 0, 0, screenW, screenH, SRCCOPY); 

ReleaseDC(hwnd, hdcForm); 
ReleaseDC(NULL, hdcScreen); 

它的那麼簡單。

valter

相關問題