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.
closed account (N36fSL3A)
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.