如何从openGL屏幕写入PNG文件?

时间:2013-10-04 04:47:53

标签: c++ image opengl

所以我有这个脚本将显示数据读入字符数组pixels

        typedef unsigned char uchar;
        // we will store the image data here
        uchar *pixels;
        // the thingy we use to write files
        FILE * shot;
        // we get the width/height of the screen into this array
        int screenStats[4];

        // get the width/height of the window
        glGetIntegerv(GL_VIEWPORT, screenStats);

        // generate an array large enough to hold the pixel data 
        // (width*height*bytesPerPixel)
        pixels = new unsigned char[screenStats[2]*screenStats[3]*3];
        // read in the pixel data, TGA's pixels are BGR aligned
        glReadPixels(0, 0, screenStats[2], screenStats[3], 0x80E0, 
        GL_UNSIGNED_BYTE, pixels);

通常情况下,我将其保存为TGA文件,但由于这些文件非常庞大,我希望使用PNG,因为我很快就会用尽硬盘空间(我的图像非常单调,易于压缩,所以潜在的收益是巨大的)。所以我在看PNG writer,但我愿意接受其他建议。他们在their website提供的用法示例如下:

#include <pngwriter.h>


int main()
{
pngwriter image(200, 300, 1.0, "out.png");
image.plot(30, 40, 1.0, 0.0, 0.0); // print a red dot
image.close();
return 0;
}

由于我对图像处理有些新意,我对我的pixels数组的形式有点困惑,以及如何将其转换为上述格式中可表示的形式。作为参考,我一直在使用以下脚本将我的文件转换为TGA:

    //////////////////////////////////////////////////
    // Grab the OpenGL screen and save it as a .tga //
    // Copyright (C) Marius Andra 2001              //
    // http://cone3d.gz.ee  EMAIL: cone3d@hot.ee    //
    //////////////////////////////////////////////////
    // (modified by me a little)
    int screenShot(int const num)
    {
        typedef unsigned char uchar;
        // we will store the image data here
        uchar *pixels;
        // the thingy we use to write files
        FILE * shot;
        // we get the width/height of the screen into this array
        int screenStats[4];

        // get the width/height of the window
        glGetIntegerv(GL_VIEWPORT, screenStats);

        // generate an array large enough to hold the pixel data 
        // (width*height*bytesPerPixel)
        pixels = new unsigned char[screenStats[2]*screenStats[3]*3];
        // read in the pixel data, TGA's pixels are BGR aligned
        glReadPixels(0, 0, screenStats[2], screenStats[3], 0x80E0, 
        GL_UNSIGNED_BYTE, pixels);

        // open the file for writing. If unsucessful, return 1
        std::string filename = kScreenShotFileNamePrefix + Function::Num2Str(num) + ".tga";

        shot=fopen(filename.c_str(), "wb");

        if (shot == NULL)
            return 1;

        // this is the tga header it must be in the beginning of 
        // every (uncompressed) .tga
        uchar TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};
        // the header that is used to get the dimensions of the .tga
        // header[1]*256+header[0] - width
        // header[3]*256+header[2] - height
        // header[4] - bits per pixel
        // header[5] - ?
        uchar header[6]={((int)(screenStats[2]%256)),
        ((int)(screenStats[2]/256)),
        ((int)(screenStats[3]%256)),
        ((int)(screenStats[3]/256)),24,0};

        // write out the TGA header
        fwrite(TGAheader, sizeof(uchar), 12, shot);
        // write out the header
        fwrite(header, sizeof(uchar), 6, shot);
        // write the pixels
        fwrite(pixels, sizeof(uchar), 
        screenStats[2]*screenStats[3]*3, shot);

        // close the file
        fclose(shot);
        // free the memory
        delete [] pixels;

        // return success
        return 0;
    }

我通常不喜欢在这些论坛上转储和保释,但在这种情况下,我只是被卡住了。我确信转换接近于微不足道我只是对图像处理不够了解才能完成。如果有人可以提供一个简单的例子来说明如何将pixels数组转换为PNG编写器库中的image.plot(),或者提供一种使用不同库来实现这一目标的方法,这将非常棒!感谢。

1 个答案:

答案 0 :(得分:5)

您当前的实施几乎完成了所有工作。您所要做的就是将PNGL返回的像素颜色写入PNG文件。由于PNG Writer中没有方法可以传递颜色数组,因此您必须逐个写入像素。

您对glReadPixels()的来电隐藏了所请求的颜色格式。您应该使用其中一个预定义常量(请参阅format argument)而不是0x80E0。根据你如何构建像素阵列,我猜你要求红色/绿色/蓝色组件。

因此,您的像素到png代码可能如下所示:

const std::size_t image_width( screenStats[2] );
const std::size_t image_height( screenStats[3] );

pngwriter image( image_width, image_height, /*…*/ );

for ( std::size_t y(0); y != image_height; ++y )
  for ( std::size_t x(0); x != image_width; ++x )
    {
       unsigned char* rgb( pixels + 3 * (y * image_width + x) );
       image.plot( x, y, rgb[0], rgb[1], rgb[2] );
    }

image.close()

作为PNGwriter的替代方案,您可以查看libclaw或按原样使用libpng