【问题标题】:C: Trouble when trying to comvert HBITMAP into .bmp fileC: 尝试将 BITMAP 转换为 .bmp 文件时出现问题
【发布时间】:2019-09-18 17:32:13
【问题描述】:

我正在创建一个函数来将屏幕截图保存到 .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 中有关此主题的所有问题,但没有一个问题为我阐明了问题。

【问题讨论】:

  • 您正在混合文件 I/O API。您不能将WriteFile()fopen() 一起使用。您需要 1) 将 WriteFile() 更改为 fwrite(),或 2) 将 fopen() 更改为 CreateFile()(并将 fclose() 更改为 CloseHandle())。另外,请参阅 MSDN 上的Bitmap Storage,其中解释了.bmp 文件的正确 格式。
  • bmp文件也必须以BITMAPFILEHEADER开头

标签: c winapi bitmap bmp hbitmap


【解决方案1】:
bitmapInfo.bmiHeader.biSize = screenWidth * screenHeight * 3;

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

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

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

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

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

您可能希望避免使用typedef unsigned char u8; 等。您可以包含&lt;stdint.h&gt; 并使用标准类型uint8_tuint16_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);
}

【讨论】:

    猜你喜欢
    • 2014-08-29
    • 1970-01-01
    • 2022-01-08
    • 2020-07-10
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多