0

我正在创建一个将屏幕截图保存到.bmp文件中的功能,我已设法将屏幕保存到一个文件中,HBITMAP但保存时遇到了问题。我会很感激一些帮助。

这是带有函数的标题:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <stdbool.h>
#include <wingdi.h>
#include <winuser.h>

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned long long u64;

void getScreen()
{
    u16 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
    u16 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);

    HDC hdc = GetDC(NULL); //get a desktop dc (NULL for entire screen)
    HDC hDest = CreateCompatibleDC(hdc); //create a dc for capture

    ReleaseDC(NULL, hdc);

    HBITMAP hbCapture = CreateCompatibleBitmap(hdc, screenWidth, screenHeight);
    SelectObject(hDest, hbCapture);

    //Copy screen to bitmap
    BitBlt(hDest, 0, 0, screenWidth, screenHeight, hdc, 0, 0, SRCCOPY);

//test
    ReleaseDC(NULL, hdc);

    char memBuffer[10000];
    BITMAPINFO bitmapInfo;
    bitmapInfo.bmiHeader.biHeight = screenHeight;
    bitmapInfo.bmiHeader.biWidth = screenWidth;
    bitmapInfo.bmiHeader.biSize = screenWidth * screenHeight * 3;
    bitmapInfo.bmiHeader.biCompression = BI_RGB;//NOT SURE
    bitmapInfo.bmiHeader.biPlanes = 1;
    bitmapInfo.bmiHeader.biBitCount = 8; //NOT SURE
    bitmapInfo.bmiHeader.biClrImportant = 0;
    GetDIBits(hDest, hbCapture, 0, screenHeight, &memBuffer, &bitmapInfo, DIB_RGB_COLORS);

    FILE * fPointer = fopen("screen.png", "wb");//TO CHANGE
    WriteFile(fPointer, &memBuffer, (WORD) sizeof(memBuffer), 0, NULL);

    fclose(fPointer);
//test

    //Clean up
    ReleaseDC(NULL, hdc);
    DeleteDC(hDest);
    DeleteObject(hbCapture);
}

这也是main.c:

#include "main.h"

int main()
{
    getScreen();

    return 0;
}

我已经阅读了 StackOverflow 中有关此主题的所有问题,但没有一个为我澄清了这个问题。

4

1 回答 1

0
bitmapInfo.bmiHeader.biSize = screenWidth * screenHeight * 3;

biSize不是总像素数,而是位图信息结构的大小,它总是sizeof(BITMAPINFOHEADER).

你想设置bitmapInfo.bmiHeader.biSizeImage。该值大致为 ( width * height * bits_per_pixel/8),但必须对其进行调整,因为每一行都已填充。也不要将fopen句柄与CreateFile注释中所述的句柄混合使用。

fopen("screen.png", "wb");

您无法使用此方法保存为 png 格式。对于 png 格式,您需要一个不同的库,例如 Gdiplus。

要保存为位图,您必须设置BITMAFILEHEADERBITMAPINFOHEADER并将它们写入文件,然后写入从获得的位GetDIBits

您可能希望避免使用typedef unsigned char u8;etc。您可以包含<stdint.h>和使用标准类型uint8_t,uint16_tuint32_t 。或者您可以使用标准 Windows 类型,例如BYTE

void getScreen()
{
    int screenWidth  = GetSystemMetrics(SM_CXVIRTUALSCREEN);
    int screenHeight  = GetSystemMetrics(SM_CYVIRTUALSCREEN);

    HDC hdc = GetDC(NULL);
    HDC hDest = CreateCompatibleDC(hdc);
    HBITMAP hbCapture = CreateCompatibleBitmap(hdc, screenWidth , screenHeight );
    HBITMAP oldbmp = (HBITMAP)SelectObject(hDest, hbCapture);
    BitBlt(hDest, 0, 0, screenWidth , screenHeight , hdc, 0, 0, SRCCOPY);

    WORD bpp = 24; //<- bits per pixel
    int size = ((screenWidth  * bpp + 31) / 32) * 4 * screenHeight ;

    BITMAPINFOHEADER bmp_info_hdr;
    bmp_info_hdr.biSize = sizeof(bmp_info_hdr);
    bmp_info_hdr.biHeight  = screenHeight ;
    bmp_info_hdr.biWidth  = screenWidth ;
    bmp_info_hdr.biPlanes = 1;
    bmp_info_hdr.biBitCount = bpp;
    bmp_info_hdr.biCompression = BI_RGB;
    bmp_info_hdr.biSizeImage = size;

    BITMAPFILEHEADER bmp_file_hdr;
    bmp_file_hdr.bfType = (WORD)'MB';
    bmp_file_hdr.bfOffBits = sizeof(bmp_file_hdr) + sizeof(bmp_info_hdr);
    bmp_file_hdr.bfSize = bmp_file_hdr.bfOffBits + size;

    char *buffer = malloc(size);
    GetDIBits(hDest, hbCapture, 0, screenHeight , buffer, 
        (BITMAPINFO*)&bmp_info_hdr, DIB_RGB_COLORS);

    FILE * fPointer = fopen("screen.bmp", "wb");
    fwrite((char*)&bmp_file_hdr, sizeof(bmp_file_hdr), 1, fPointer);
    fwrite((char*)&bmp_info_hdr, sizeof(bmp_info_hdr), 1, fPointer);
    fwrite(buffer, size, 1, fPointer);
    fclose(fPointer);

    free(buffer);

    SelectObject(hDest, oldbmp);
    DeleteObject(hbCapture);
    DeleteDC(hDest);
    ReleaseDC(NULL, hdc);
}
于 2019-09-18T20:24:07.130 回答