2014-02-07 8 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 코드. 나는이 경우 내 DLL 함수 create_array()를 사용하고, 다시

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

,하지만 난 당신이 무엇을 말할 수 있어야한다고 생각 :

SDL에 질감과 버퍼를 생성하는 코드는 .

결과 이미지는 이것이다 :

The image output from my program 더 나은 방법이나이 일을 순수 SDL 방법을 추가하시기 바랍니다. GetPixel() 시도하고 올바른 값을 반환합니다. 그것은 여러 호출에 대한 높은 오버 헤드가 있습니다.

+0

잠재적 인 문제는 호환되는 비트 맵을 만드는 위치입니다. 비트 맵은 SDL 비트 맵의 ​​크기가 아니라 디스플레이의 정확한 크기로 만들어야합니다. 당신은 당신이 보는 것처럼 결과를 얻을 수 있기 때문에 GDI가 비트 맵의 ​​크기를 줄 이도록하고 싶지 않습니다. – BitBank

+0

간단한 스크린 샷을 만들 때 sdl을 사용하는 이유는 무엇입니까? winapi를 사용하면 최소한의 코딩으로 동일한 결과를 얻을 수 있습니다. –

+0

@BitBank 나는 그것을 바꿨지 만 그것을 완전히 고치지 못했고 이미지를 조금 더 좋게 만들었습니다. – 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