Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Need help taking a screenshot

  1. #1
    Junior Member Newbie
    Join Date
    Aug 2013
    Posts
    12

    Need help taking a screenshot

    I'm looking for advice from someone who is knowledgable, or could become so, about .bmp files. I'm currently trying to make a function that will take a screenshot and output it as a .bmp file. I almost have it working (it works perfectly if the screen has dimensions that are multiples of 4), but I am having trouble padding the file properly. To my knowledge, the pixel array is supposed to be padded to have row sizes that are multiples of 4 bytes. The code I have so far is:

    Code :
    void ExportScreen()
    {
        const int WindowWidth = glutGet(GLUT_WINDOW_WIDTH);
        const int WindowHeight = glutGet(GLUT_WINDOW_HEIGHT);
        const int PixelperMeterH = 1000.f*(float)glutGet(GLUT_SCREEN_HEIGHT)/glutGet(GLUT_SCREEN_HEIGHT_MM);
        const int PixelperMeterW = 1000.f*(float)glutGet(GLUT_SCREEN_WIDTH)/glutGet(GLUT_SCREEN_WIDTH_MM);
     
        GLubyte* Pixels = new GLubyte[ 3 * WindowWidth * WindowHeight ];
        glReadPixels( 0, 0, WindowWidth, WindowHeight, GL_BGR, GL_UNSIGNED_BYTE, Pixels );
     
        int NumPads = WindowWidth%4;
        vector<GLubyte> ImageData( Pixels, Pixels + (3*WindowWidth*WindowHeight) );
        vector<int> Indicies;
        for ( int i = 0; i < ImageData.size()/3; i++ )
        {
            if ( i%WindowWidth == WindowWidth - 1 )
            {
                Indicies.push_back(3*i+3);
            }
        }
        for ( int i = 0; i < Indicies.size(); i++ )
        {
            for ( int j = 0; j < NumPads; j++ )
            {
                ImageData.insert( ImageData.begin() + Indicies[i] + NumPads*i + j, 'N' );
            }
        }
     
        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 = 0x4D42;
        Header.ByteSize = ( 4 * floor( (24 * WindowWidth + 31)/32.f ) * WindowHeight ) + 54;
        Header.Empty = 0;
        Header.Useless = 0;
        Header.PA_Adress = 54;
     
        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 = PixelperMeterW;
        DIB_Header.VertRes = PixelperMeterH;
        DIB_Header.Colors = 0;
        DIB_Header.ImportantColors = 0;
     
        stringstream Temp;
        int Current = 0;
        while ( 1 )
        {
            Temp.str("");
            Temp<<"Screenshots/Screenshot_"<<Current<<".bmp";
            ifstream Check( Temp.str().c_str() );
            if ( Check.is_open() )
                Current++;
            else
                break;
        }
     
        ofstream ScreenShot( Temp.str().c_str(), ostream::binary );
     
        WriteByte2( ScreenShot, Header.Ident );
        WriteByte4( ScreenShot, Header.ByteSize );
        WriteByte2( ScreenShot, Header.Empty );
        WriteByte2( ScreenShot, Header.Useless );
        WriteByte4( ScreenShot, Header.PA_Adress );
        WriteByte4( ScreenShot, DIB_Header.ByteSize );
        WriteByte4( ScreenShot, DIB_Header.PixelWidth );
        WriteByte4( ScreenShot, DIB_Header.PixelHeight );
        WriteByte2( ScreenShot, DIB_Header.Planes );
        WriteByte2( ScreenShot, DIB_Header.BBP );
        WriteByte4( ScreenShot, DIB_Header.CompressionMethod );
        WriteByte4( ScreenShot, DIB_Header.ImageSize );
        WriteByte4( ScreenShot, DIB_Header.HorizRes );
        WriteByte4( ScreenShot, DIB_Header.VertRes );
        WriteByte4( ScreenShot, DIB_Header.Colors );
        WriteByte4( ScreenShot, DIB_Header.ImportantColors );
        ScreenShot.write( (char*)Pixels, ImageData.size() );
     
        WritetoLog("Captured screen successfully");
    }

  2. #2
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    474
    Quote Originally Posted by Niven07 View Post
    I'm currently trying to make a function that will take a screenshot and output it as a .bmp file. I almost have it working (it works perfectly if the screen has dimensions that are multiples of 4), but I am having trouble padding the file properly. To my knowledge, the pixel array is supposed to be padded to have row sizes that are multiples of 4 bytes.
    Note that OpenGL also pads pixel data to a multiple of 4 bytes by default, although this can be changed with glPixelStorei(GL_PACK_ALIGNMENT). With the default 4-byte alignment, you should just be able to write the data returned by glReadPixels() directly to the file (preceded by the BMP headers), although you'll need to allocate a larger buffer than "width * height * 3", e.g.:

    Code :
    size_t stride = (WindowWidth * 3 + (4-1))/4*4;
    GLubyte* Pixels = new GLubyte[ stride * WindowHeight ];

  3. #3
    Junior Member Newbie
    Join Date
    Aug 2013
    Posts
    12
    Quote Originally Posted by GClements View Post
    Note that OpenGL also pads pixel data to a multiple of 4 bytes by default
    Wish I had known that sooner. I'll have to do a little more research on functions next time I try something like this. Also, thank you for the advice. I have the function working correctly now.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •