Fran
Fran

Reputation: 77

BMP screenshot in OpenGL

I´m trying to take a screenshot in BMP format of the application I´m running. It takes well the screenshot when it is windowed, doesn´t matter the size of the window it works well. But, when I put my application in fullscreen using glutFullScreen() it doesn´t save the BMP file properly. Any ideas why does it happen?

This is the function call

hacerCaptura(ancho, alto);

where

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

Here is the code:

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

Upvotes: 0

Views: 570

Answers (1)

Xirema
Xirema

Reputation: 20396

I suspect the offending line is this one:

cabeceraBMP.bfSize = sizeof (BITMAPFILEHEADER);

From the documentation for BITMAPFILEHEADER:

bfSize The size, in bytes, of the bitmap file.

So the correct value for bfSize is sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + anchura * altura * 3.

I tested this with a small, 20x20 bitmap I created to test with:

Raw Data Values of bitmap image

Which matches the values you'd expect based on the standardized bitmap format.

I haven't sanity-checked all your other required fields, but my advice is that you refer to the documentation pages and make sure you're substituting in the correct values for all of those fields.

Edit:

There's another potential issue that may be affecting your image output.

The Bitmap format expects all your rows of bitmap data to be aligned with up to 3 bytes of padding depending on the actual row length, so that each row of data is a multiple of four bytes. This isn't a big deal if your image width is a multiple of 4 (like 1920x1080) but could become a problem if you're using a resolution that doesn't line up neatly like that (like 1366x768, which is a very common pre-1080p resolution). If your resolution is unusual, check and make sure the data from glReadPixels is properly padded, and if it isn't, transform it so that it is.

Upvotes: 1

Related Questions