Taking a screenshot in opengl
Sep 14, 2013 at 12:57am UTC
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.
Sep 14, 2013 at 1:00am UTC
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 Sep 14, 2013 at 1:00am UTC
Sep 14, 2013 at 1:23am UTC
#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 Sep 14, 2013 at 1:38am UTC
Sep 14, 2013 at 1:53am UTC
Thank you for the advice and the article. I've read through it and have now fixed the problems that I was having.
Sep 14, 2013 at 2:11am UTC
Topic archived. No new replies allowed.