OpenGL 中的 BMP 屏幕截图

Posted

技术标签:

【中文标题】OpenGL 中的 BMP 屏幕截图【英文标题】:BMP screenshot in OpenGL 【发布时间】:2017-01-10 16:17:41 【问题描述】:

我正在尝试为我正在运行的应用程序截取 BMP 格式的屏幕截图。窗口化时可以很好地截取屏幕截图,无论窗口大小都可以正常工作。但是,当我使用 glutFullScreen() 将我的应用程序置于全屏模式时,它不会正确保存 BMP 文件。任何想法为什么会发生?

这是函数调用

hacerCaptura(ancho, alto);

在哪里

ancho = glutGet(GLUT_SCREEN_WIDTH);
alto  = glutGet(GLUT_SCREEN_HEIGHT);

代码如下:

    void hacerCaptura(int anchura, int altura)

    BMP_Data = malloc (anchura * altura * 3);
    memset (BMP_Data, 0, anchura * altura * 3);

    glReadPixels (0, 0, anchura, altura, GL_RGB, GL_UNSIGNED_BYTE, BMP_Data);
    guardaBMP ("captura.bmp", anchura, altura, (unsigned char*)BMP_Data);

    free (BMP_Data);



    int guardaBMP (char *filename, int anchura, int altura, unsigned char *BMP_Data)

    FILE *punteroFich;
    BITMAPINFOHEADER infoBMP;
    BITMAPFILEHEADER cabeceraBMP;
    unsigned int contador;
    unsigned char tempRGB;

    punteroFich = fopen (filename, "wb"); 
    if (!punteroFich)
    
        return 0;
    

    cabeceraBMP.bfOffBits = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER);
    cabeceraBMP.bfReserved1 = 0;
    cabeceraBMP.bfReserved2 = 0;
    cabeceraBMP.bfSize = sizeof (BITMAPFILEHEADER);
    cabeceraBMP.bfType = 0x4D42; 

    infoBMP.biBitCount = 24;
    infoBMP.biClrImportant = 0;
    infoBMP.biClrUsed = 0;
    infoBMP.biCompression = BI_RGB;
    infoBMP.biHeight = altura;
    infoBMP.biPlanes = 1;
    infoBMP.biSize = sizeof (BITMAPINFOHEADER);
    infoBMP.biSizeImage = anchura * abs (altura) * 3;
    infoBMP.biWidth = anchura;
    infoBMP.biXPelsPerMeter = 0;
    infoBMP.biYPelsPerMeter = 0;

    for (contador = 0; contador < infoBMP.biSizeImage; contador += 3)
    
        tempRGB = BMP_Data [contador];
        BMP_Data [contador] = BMP_Data [contador + 2];
        BMP_Data [contador + 2] = tempRGB;
    

    fwrite (&cabeceraBMP, 1, sizeof (BITMAPFILEHEADER), punteroFich);
    fwrite (&infoBMP, 1, sizeof (BITMAPINFOHEADER), punteroFich);
    fwrite (BMP_Data, 1, infoBMP.biSizeImage, punteroFich);

    fclose (punteroFich);
    return 1;

【问题讨论】:

“它没有正确保存 BMP 文件”真的很模糊。究竟是什么问题?该文件根本没有创建?文件已损坏?图片尺寸不对? 很抱歉。文件已创建,它不是空的,但格式不正确,就是这么说的。 什么说格式不正确? Windows 10 的照片应用程序在尝试查看它是否有效时。它不会用 Photoshop 或其他任何东西打开。 这个问题可能应该被标记为“C”,而不是“C++”。我没有看到在这段代码中使用了一个单一的 C++ 概念,并且我为修复它提供的建议会因平台而异。 【参考方案1】:

我怀疑有问题的行是这一行:

cabeceraBMP.bfSize = sizeof (BITMAPFILEHEADER);

来自documentation for BITMAPFILEHEADER:

bfSize 位图文件的大小,以字节为单位。

所以bfSize 的正确值是sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + anchura * altura * 3

我用我创建的一个小 20x20 位图进行了测试:

这与您根据 standardized bitmap format 期望的值匹配。

我没有仔细检查您所有其他必填字段,但我的建议是您参考文档页面并确保您为所有这些字段替换了正确的值。

编辑:

还有另一个潜在问题可能会影响您的图像输出。

位图格式要求您的所有位图数据行与最多 3 个字节的填充对齐,具体取决于实际行长度,因此每行数据都是 4 个字节的倍数。如果您的图像宽度是 4 的倍数(例如 1920x1080),这没什么大不了的,但如果您使用的分辨率不是这样整齐排列(例如 1366x768,这是一个非常常见的1080p 之前的分辨率)。如果您的分辨率不正常,请检查并确保来自glReadPixels 的数据被正确填充,如果不是,则将其转换为正确。

【讨论】:

非常感谢。正如您所指出的,尺寸存在问题。此外,正如您在编辑中所说,我必须填充来自 glReadPixels 的数据以使我的图像宽度成为 4 的倍数。现在,一切正常。

以上是关于OpenGL 中的 BMP 屏幕截图的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SDL 2 中获取并保存 BMP 屏幕截图?

使用 openGL 和/或 X11 的屏幕截图

PNG格式的屏幕截图有效,但不是BMP格式

OpenGL ES:屏幕截图显示设备和模拟器之间的不同

iOS开发- OpenGL ES屏幕截图

MFC 屏幕截图(libjpeg bmp转jpg)