我一直在尝试制作一个 SDL 程序,该程序能够截取整个屏幕的屏幕截图,在本例中,可以显示整个显示器屏幕的实时反馈。我已经成功地使用 GDI 函数检索图像,但我不知道在 GetDIBits() 函数返回后如何正确处理缓冲区中的数据输出。到目前为止,我的图像与预期输出相差甚远。我目前尝试过的所有格式的颜色都困惑不堪,其中大多数可用于 SDL 纹理的 32 位和 24 位像素格式。我的 win32 代码也可能有一个错误,我不完全确定,因为显示的图像不正确。
以下是我获取屏幕截图的方法:
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(),但我认为您应该能够知道它的作用。
生成的图像是这样的:
请随意添加更好的方法或纯 SDL 方法来执行此操作。我尝试过 GetPixel(),它返回正确的值。但多次调用的开销很高。
最佳答案
用于捕获屏幕并将其绘制到表单的代码:
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);
就这么简单。
瓦尔特
关于c - 处理 GetDIBits() 返回的像素缓冲区的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21639837/