C++에서 OpenGL 창의 스크린 샷을 가져 와서 파일에 저장하는 방법.OpenGL에서 스크린 샷 찍는 방법
glReadPixels()
함수를 찾았습니다. 하지만 다음에 무엇을해야할지 모르겠습니다. 예를 들어 파일 경로를 설정할 수있는 곳은 어디입니까?
어렵지 않은 경우 코드를 작성하십시오.
C++에서 OpenGL 창의 스크린 샷을 가져 와서 파일에 저장하는 방법.OpenGL에서 스크린 샷 찍는 방법
glReadPixels()
함수를 찾았습니다. 하지만 다음에 무엇을해야할지 모르겠습니다. 예를 들어 파일 경로를 설정할 수있는 곳은 어디입니까?
어렵지 않은 경우 코드를 작성하십시오.
glReadPixels은 사용자가 제공하는 메모리 버퍼에 비트를 복사합니다. 수동으로 데이터를 원하는 형식의 이미지로 포맷하고 glReadPixels이 반환 된 후에 디스크에 기록해야합니다.
파일에 해당 데이터를 저장하면 OpenGL에 해당 기능을 제공하지 않거나 제 3 자 라이브러리를 사용해야합니다.
Windows .bmp는 자신이 직접 작성하려고하는 경우 가장 쉽습니다. 위키 백과는 pretty good explanation of the file format입니다. 그렇지 않으면 저수준 제어를 위해 이미지 저장/로딩 라이브러리 libpng, libjpeg 등을 사용할 수 있습니다. 또는 devIL (다른 것들도 있지만 이것은 내가 좋아하는 것이며 GL과 잘 어울리는 매우 다재다능한 라이브러리입니다) 레벨 "그냥 해"이미지 I/O.
이 코드 조각은 OpenGL 창을 캡처하고 BMP 파일로 내 보냅니다. 실행하려면 FreeImage 라이브러리가 있어야합니다.
// 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;
'glPixelStorei (GL_UNPACK_ALIGNMENT, 1);'은'glReadPixels' 전에 좋은 생각입니다 ([OpenGL Wiki] (http://www.opengl.org/wiki/GLAPI/glPixelStore)에서 더 읽으십시오) – Mortennobel
사용하는 것이 현명합니까? '''BY_'' 대신''GL_UNSIGNED_BYTE''도 배열에 사용합니다. – Riot
죄송합니다, 저는'''GLubyte''를 의미했습니다. – Riot
일반적으로 OpenGL은 이미지 저장 기능을 제공하지 않습니다. 이 작업을 수행하는 가장 빠르고 간단한 방법은 저장하는 것입니다. PPM 형식입니다. 그러나 이러한 종류의 형식은 압축되지 않았으므로 파일 크기가 매우 클 수 있습니다. 그리고 그것은 요즘 꽤 많은 프로그램에 의해서만 지원 될 수 있습니다.
압축 된 .png 파일에 이미지를 저장하는 것을 선호하지만 무손실 이미지를 제공하고 많은 브라우저에서 지원됩니다. OpenGL을 .png 형식으로 저장하려면 먼저 PNGwriter을 권장합니다. 그것은 매우 간단하고 사용하기 쉽습니다.
pngwriter PNG(width, height, 1.0, fileName); // "1.0" stand for the white background
PNG.plot(x, y, R, G, B);
PNG.close();
예를 들어, 위치의 색 (R, G, B) (X, Y) 코드가 될합니다 (PNGwriter 사이트에서 볼 "빠른")한다 갖는 화상의 화소를 저장할 PNGwriter는 이미지의 왼쪽 상단부터 시작하여 각 픽셀을 저장하므로 배열이 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();
의 Runnable 예를
당신이 창을 마우스로 클릭 할 때마다이하는 tmpX.ppm
파일은 현재 스크린 샷으로 작성됩니다.
Linux에서이 파일을 eog
과 같이 볼 수 있으며 텍스트 편집기로 검사 할 수 있습니다.
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glext.h>
static GLubyte *pixels = NULL;
static const GLenum FORMAT = GL_RGBA;
static const GLuint FORMAT_NBYTES = 4;
static const unsigned int HEIGHT = 500;
static const unsigned int WIDTH = 500;
static unsigned int nscreenshots = 0;
static unsigned int time;
/* Model. */
static double angle = 0;
static double angle_speed = 45;
static void init(void) {
glReadBuffer(GL_BACK);
glClearColor(0.0, 0.0, 0.0, 0.0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glViewport(0, 0, WIDTH, HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
pixels = malloc(FORMAT_NBYTES * WIDTH * HEIGHT);
time = glutGet(GLUT_ELAPSED_TIME);
}
static void deinit(void) {
free(pixels);
}
static void create_ppm(char *prefix, int frame_id, unsigned int width, unsigned int height,
unsigned int color_max, unsigned int pixel_nbytes, GLubyte *pixels) {
size_t i, j, k, cur;
enum Constants { max_filename = 256 };
char filename[max_filename];
snprintf(filename, max_filename, "%s%d.ppm", prefix, frame_id);
FILE *f = fopen(filename, "w");
fprintf(f, "P3\n%d %d\n%d\n", width, HEIGHT, 255);
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
cur = pixel_nbytes * ((height - i - 1) * width + j);
fprintf(f, "%3d %3d %3d ", pixels[cur], pixels[cur + 1], pixels[cur + 2]);
}
fprintf(f, "\n");
}
fclose(f);
}
static void draw_scene() {
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glRotatef(angle, 0.0f, 0.0f, -1.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.5f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.5f, -0.5f, 0.0f);
glEnd();
}
static void display(void) {
draw_scene();
glutSwapBuffers();
glReadPixels(0, 0, WIDTH, HEIGHT, FORMAT, GL_UNSIGNED_BYTE, pixels);
}
static void idle(void) {
int new_time = glutGet(GLUT_ELAPSED_TIME);
angle += angle_speed * (new_time - time)/1000.0;
angle = fmod(angle, 360.0);
time = new_time;
glutPostRedisplay();
}
void mouse(int button, int state, int x, int y) {
if (state == GLUT_DOWN) {
puts("screenshot");
create_ppm("tmp", nscreenshots, WIDTH, HEIGHT, 255, FORMAT_NBYTES, pixels);
nscreenshots++;
}
}
int main(int argc, char **argv) {
GLint glut_display;
glutInit(&argc, argv);
glutInitWindowSize(WIDTH, HEIGHT);
glutInitWindowPosition(100, 100);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutIdleFunc(idle);
glutMouseFunc(mouse);
atexit(deinit);
glutMainLoop();
return EXIT_SUCCESS;
}
컴파일과 :
gcc main.c -lm -lGL -lGLU -lglut
우분투 15.10에서 테스트, OpenGL은 NVIDIA 352.63은 4.5.0.
메모리 버퍼를 디스크에 쓸 수있는 기능은 무엇입니까? – EthanHunt
@EthanHunt :'fwrite'는 FILE *에 데이터를 쓰고,'fopen'은 지정한 파일 이름에 해당하는 FILE *을줍니다. 그러나 이미지 형식에 관한 부분을 무시하지 마십시오. 까다로운 부분입니다. –
예제 코드를 줄 수 있습니까? – EthanHunt