如何在OpenGL中截图 如何在C++中截取OpenGL窗口的截图并将其保存到文件.< /P>
我找到了函数, 但我不知道下一步该怎么办。例如,我可以在哪里设置文件的路径如何在OpenGL中截图 如何在C++中截取OpenGL窗口的截图并将其保存到文件.< /P>,c++,opengl,save,screenshot,glreadpixels,C++,Opengl,Save,Screenshot,Glreadpixels,我找到了函数, 但我不知道下一步该怎么办。例如,我可以在哪里设置文件的路径 如果不难,请编写代码。会将位复制到您提供的内存缓冲区中。您必须手动格式化数据(按照您选择的图像格式),并在返回后将其写入磁盘。将该数据保存到文件是您必须自己完成的事情,或者使用第三方库进行保存-OpenGL没有此类功能 如果你想自己动手的话,Windows.bmp可能是最简单的——维基百科有一个。否则,您可以使用图像保存/加载库:libpng、libjpeg等进行低级控制,或者(还有其他库,但这是我最喜欢的,它是一个非常
如果不难,请编写代码。会将位复制到您提供的内存缓冲区中。您必须手动格式化数据(按照您选择的图像格式),并在返回后将其写入磁盘。将该数据保存到文件是您必须自己完成的事情,或者使用第三方库进行保存-OpenGL没有此类功能
如果你想自己动手的话,Windows.bmp可能是最简单的——维基百科有一个。否则,您可以使用图像保存/加载库:libpng、libjpeg等进行低级控制,或者(还有其他库,但这是我最喜欢的,它是一个非常通用的库,与GL配合使用)进行高级“只需执行”图像i/o。这段代码捕获OpenGL窗口并导出为BMP文件。您必须有库才能运行它
// 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;
通常,OpenGL不提供保存图像的功能。我认为最快和最简单的方法就是保存到。格式。然而,这种格式是未压缩的,这意味着它的文件大小将非常大。如今,它只能由相当多的项目来支持 我更喜欢将图像保存到.png文件中,该文件经过压缩,但也提供无损图像,并且受到许多浏览器的支持。要将OpenGL保存为.png格式,我首先推荐。它非常简单,易于使用。例如,要在位置(x,y)保存颜色为(R,G,B)的图像像素,您的代码将是(请参阅PNGwriter网站中的“快速启动”): 请注意,由于PNGwriter从图像的左上角开始保存每个像素,而数组get from glReadPixels()从窗口的左下角开始,因此保存整个图像的代码可能如下所示:
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();
GLfloat*像素=新的GLfloat[nPixels];
glReadPixels(0.0、0.0、宽度、高度、GL_RGB、GL_浮点、像素);
pngwriter PNG(宽度、高度、1.0、文件名);
尺寸x=1;
尺寸y=1;
双R,G,B;
对于(大小i=0;i可运行示例
每次用鼠标单击窗口时,都会使用当前屏幕截图创建一个tmpX.ppm
文件
例如,您可以在Linux上使用eog
查看此文件,并使用文本编辑器检查它
要在不显示窗口的情况下进行渲染,请参见:
在Ubuntu 15.10、OpenGL 4.5.0和NVIDIA 352.63上测试
Vulkan
这个例子刚刚奏效:如何运行它:
一个简单快速的解决方案
- 输出TARGA文件,但可以轻松转换为PNG(提供脚本)
- 不需要额外的库
将同时使用C和C++(有一些小的更改)。
- 注意:输出文件应具有
tga
文件扩展名
代码如下:
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");
}
并调用该函数:
saveScreenshotToFile("test.tga", 1200, 900);
用于将TARGA文件转换为PNG的bash脚本:
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
您可以使用@Rafael的答案和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);
}
感谢OpenCV:使用什么函数可以将内存缓冲区写入磁盘?@EthanHunt:fwrite
将数据写入文件*,fopen
将为您提供一个与指定文件名对应的文件*。但不要忽略图像格式部分,这是一个棘手的部分。对于arr,使用GL\u UNSIGNED\u BYTE
是明智的也可以,而不是windows特定的BYTE
。对不起,我的意思是GLubyte
@Mortennobel如果使用GL|u PACK_ALIGNMENT
,会更好,因为glReadPixels
是打包而不是解包:)另请参见:PPM | PNG | FFMPEG一个。
saveScreenshotToFile("test.tga", 1200, 900);
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
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);
}