How to take screenshot in OpenGL

前端 未结 7 704
终归单人心
终归单人心 2020-12-01 04:59

How to take a screenshot of an OpenGL window in C++ and save it to file.

I found the glReadPixels() function, but I don\'t know what to do next. Where I can set path

相关标签:
7条回答
  • 2020-12-01 05:11

    glReadPixels will copy the bits into a memory buffer that you supply. You have to manually format the data (to the image format of your choice) and write it to disk after glReadPixels returns.

    0 讨论(0)
  • 2020-12-01 05:14

    You can save screenshot with @Rafael's answer and OpenCV:

    void Game::saveScreenshotToFile(std::string filename, int windowWidth, int windowHeight) {    
    
        cv::Mat img(windowHeight, windowWidth, CV_8UC3);
        glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4);
    
        glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());
        glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);
        cv::flip(img, img, 0);
        //cv::imshow("Image",img);
        //cv::waitKey(0);
        cv::imwrite(filename, img);
        }
    

    Thanks for OpenCV: https://stackoverflow.com/a/9098883/10152334

    0 讨论(0)
  • 2020-12-01 05:15

    This piece of code captures the OpenGL window and export to a BMP file. You must have FreeImage library to run it.

    // Make the BYTE array, factor of 3 because it's RBG.
    BYTE* pixels = new BYTE[3 * width * height];
    
    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
    
    // Convert to FreeImage format & save to file
    FIBITMAP* image = FreeImage_ConvertFromRawBits(pixels, width, height, 3 * width, 24, 0x0000FF, 0xFF0000, 0x00FF00, false);
    FreeImage_Save(FIF_BMP, image, "C:/test.bmp", 0);
    
    // Free resources
    FreeImage_Unload(image);
    delete [] pixels;
    
    0 讨论(0)
  • 2020-12-01 05:17

    A simple and quick solution.

    • Outputs a TARGA file but can easily be converted to PNG (script provided).
    • No extra libraries required.
    • Will work with both C and C++ (with some minor changes).
    • Note: The output file should have the tga file extension.

    Here is the code:

    void saveScreenshotToFile(std::string filename, int windowWidth, int windowHeight) {    
        const int numberOfPixels = windowWidth * windowHeight * 3;
        unsigned char pixels[numberOfPixels];
    
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
        glReadBuffer(GL_FRONT);
        glReadPixels(0, 0, windowWidth, windowHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
    
        FILE *outputFile = fopen(filename.c_str(), "w");
        short header[] = {0, 2, 0, 0, 0, 0, (short) windowWidth, (short) windowHeight, 24};
    
        fwrite(&header, sizeof(header), 1, outputFile);
        fwrite(pixels, numberOfPixels, 1, outputFile);
        fclose(outputFile);
    
        printf("Finish writing to file.\n");
    }
    

    And calling the function:

    saveScreenshotToFile("test.tga", 1200, 900);
    

    A bash script to convert TARGA files to PNG:

    for oldFileName in *.tga; do
        [ -f "$oldFileName" ] || break         # Break out if no .tga files found.
        newFileName=${oldFileName//.tga/.png}
        convert $oldFileName $newFileName
        rm $oldFileName
        echo "Converted $oldFileName to $newFileName"
    done
    
    0 讨论(0)
  • 2020-12-01 05:17

    Generally, OpenGL don't provide functions to save image. I think the fastest and simplest way to do this is save to .PPM format. However, this kind of format is uncompressed which means it's file size would be very large. And it can be support only by quite a few programs nowadays.

    I prefer to save image to .png file which is compressed but also gives lossless image and supported by many browsers. To save the OpenGL to .png format, I first recommend the PNGwriter. It's pretty simple and easy to use. For example, to save a pixel of a image with color (R, G, B) in the position (x, y), your code will be(see "quickstart" in the PNGwriter website):

    pngwriter PNG(width, height, 1.0, fileName); // "1.0" stand for the white background
    PNG.plot(x, y, R, G, B);
    PNG.close();
    

    Note that, since the PNGwriter save each pixel starting from the top-left corner of the image, while the array get from glReadPixels() start from the bottom-left of the window, your code to save the whole image might probably look like this:

    GLfloat* pixels = new GLfloat[nPixels];
    glReadPixels(0.0, 0.0, width, height,GL_RGB, GL_FLOAT, pixels);
    pngwriter PNG(width, height, 1.0, fileName);
    size_t x = 1;   
    size_t y = 1;
    double R, G, B;
    for(size_t i=0; i<npixels; i++) // "i" is the index for array "pixels"
    {
          switch(i%3)
         {
               case 2:
                     B = static_cast<double>(pixels[i]); break;
               case 1:
                     G = static_cast<double>(pixels[i]); break;
               case 0:
                     R = static_cast<double>(pixels[i]);
                     PNG.plot(x, y, R, G, B);     // set pixel to position (x, y)
                     if( x == width )             // Move to the next row of image
                     {
                           x=1;
                           y++;
                      }
                      else                       // To the next pixel
                      { x++; }
                      break;
         }
    }
    PNG.close();
    
    0 讨论(0)
  • 2020-12-01 05:19

    Saving that data to a file is something you'll either have to do yourself or use a third-party library for - OpenGL has no such feature.

    Windows .bmp is probably the easiest if you're looking to do it yourself - Wikipedia has a pretty good explanation of the file format. Otherwise you can use image saving/loading libraries: libpng, libjpeg, etc. for low-level control, or devIL (there are others, but this is my favorite, and it's an extremely versatile library that goes well with GL) for high-level "just do it" image i/o.

    0 讨论(0)
提交回复
热议问题