Taking a screenshot in opengl

I've read up on .bmp files on wikipedia and am currently attempting to make a function that can export a .bmp file of the screen of my programs. I've already begun work on it but it isn't working. The code I have so far is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
typedef char Byte;
typedef int Byte4;
typedef short Byte2;

struct BMP_Header
{
    Byte2 Ident;     /// BM
    Byte4 ByteSize;  /// Size of file in bytes
    Byte2 Empty;
    Byte2 Useless;
    Byte4 PA_Adress; /// Offset of pixel array
};

struct BMP_DIB_Header
{
    Byte4 ByteSize; /// 40
    Byte4 PixelWidth;
    Byte4 PixelHeight;
    Byte2 Planes; /// 1
    Byte2 BBP;
    Byte4 CompressionMethod;
    Byte4 ImageSize; /// Size of raw bitmap data
    Byte4 HorizRes; /// pixel per meter
    Byte4 VertRes;
    Byte4 Colors; /// 0
    Byte4 ImportantColors; /// 0
};

void ExportScreen()
{
    const int WindowWidth = glutGet(GLUT_WINDOW_WIDTH);
    const int WindowHeight = glutGet(GLUT_WINDOW_HEIGHT);
    const float PixelperMeter = 1000.f*(float)glutGet(GLUT_SCREEN_HEIGHT)/glutGet(GLUT_SCREEN_HEIGHT_MM);

    GLubyte* Pixels = new GLubyte[ 3 * WindowWidth * WindowHeight ];
    glReadPixels( 0, 0, WindowWidth, WindowHeight, GL_BGR, GL_UNSIGNED_BYTE, Pixels );

    vector<GLubyte> Padding;
    Padding.resize( 4 - WindowWidth%4 );
    for ( int i = 0; i < Padding.size(); i++ )
        Padding[i] = 0;

    vector<GLubyte> ImageData( Pixels, Pixels + (3*WindowWidth*WindowHeight) );
    for ( int i = 0; i < ImageData.size(); i++ )
    {
        if ( i%WindowWidth == WindowWidth - 1 )
        {
            ImageData.insert( ImageData.begin() + i, Padding.begin(), Padding.end() );
        }
    }

    Pixels = new GLubyte[ ImageData.size() ];
    for ( int i = 0; i < ImageData.size(); i++ )
        Pixels[i] = ImageData[i];

    BMP_Header Header;
    BMP_DIB_Header DIB_Header;

    Header.Ident = 19778;
    Header.ByteSize = ( 4 * floor( (24 * WindowWidth + 31)/32.f ) * WindowHeight ) + sizeof(BMP_Header) + sizeof(BMP_DIB_Header);
    Header.Empty = 0;
    Header.Useless = 0;
    Header.PA_Adress = sizeof(BMP_Header) + sizeof(BMP_DIB_Header);

    DIB_Header.ByteSize = 40;
    DIB_Header.PixelWidth = WindowWidth;
    DIB_Header.PixelHeight = WindowHeight;
    DIB_Header.Planes = 1;
    DIB_Header.BBP = 24;
    DIB_Header.CompressionMethod = 0;
    DIB_Header.ImageSize = Header.ByteSize - 54;
    DIB_Header.HorizRes = PixelperMeter;
    DIB_Header.VertRes = PixelperMeter;
    DIB_Header.Colors = 0;
    DIB_Header.ImportantColors = 0;

    cout<<sizeof(BMP_DIB_Header)<<" and "<<sizeof(BMP_Header)<<endl;

    ofstream ScreenShot("Screenshots/Test.bmp", ostream::binary );

    ScreenShot<<(char*)&Header.Ident
              <<(char*)&Header.ByteSize
              <<(char*)&Header.Empty
              <<(char*)&Header.Useless
              <<(char*)&Header.PA_Adress
              <<(char*)&DIB_Header.ByteSize
              <<(char*)&DIB_Header.PixelWidth
              <<(char*)&DIB_Header.PixelHeight
              <<(char*)&DIB_Header.Planes
              <<(char*)&DIB_Header.BBP
              <<(char*)&DIB_Header.CompressionMethod
              <<(char*)&DIB_Header.ImageSize
              <<(char*)&DIB_Header.HorizRes
              <<(char*)&DIB_Header.VertRes
              <<(char*)&DIB_Header.Colors
              <<(char*)&DIB_Header.ImportantColors
              <<Pixels;
}


My problems are that when less then the required amount of bytes is needed to store a value in the file, the 00 bytes are skipped (Ex. The file will contain 42 instead of 42 00 00 00), and the Pixels are stored as nothing but 0D ( every value intended for storing pixel data is 0D ). Thanks for any help in advance.
You need to pack the BMP header. The file is being padded.

1
2
3
4
5
#pragma pack(1)  // ensure structure is packed
 
// Header

#pragma pack(0)  // restore normal structure packing rules 
Last edited on
closed account (o1vk4iN6)
#pragma pack() is Visual Studio only.

http://en.cppreference.com/w/cpp/language/alignas

That's not the problem, though. He's outputting strings by converting to a pointer to a char.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    ScreenShot<<(char*)&Header.Ident
              <<(char*)&Header.ByteSize
              <<(char*)&Header.Empty
              <<(char*)&Header.Useless
              <<(char*)&Header.PA_Adress
              <<(char*)&DIB_Header.ByteSize
              <<(char*)&DIB_Header.PixelWidth
              <<(char*)&DIB_Header.PixelHeight
              <<(char*)&DIB_Header.Planes
              <<(char*)&DIB_Header.BBP
              <<(char*)&DIB_Header.CompressionMethod
              <<(char*)&DIB_Header.ImageSize
              <<(char*)&DIB_Header.HorizRes
              <<(char*)&DIB_Header.VertRes
              <<(char*)&DIB_Header.Colors
              <<(char*)&DIB_Header.ImportantColors
              <<Pixels;


Char strings are null terminated which is why it only writes up to a 0.

http://www.cplusplus.com/articles/DzywvCM9/

Last edited on
Thank you for the advice and the article. I've read through it and have now fixed the problems that I was having.
Topic archived. No new replies allowed.