2011-04-30 7 views
10

C++에서 OpenGL 창의 스크린 샷을 가져 와서 파일에 저장하는 방법.OpenGL에서 스크린 샷 찍는 방법

glReadPixels() 함수를 찾았습니다. 하지만 다음에 무엇을해야할지 모르겠습니다. 예를 들어 파일 경로를 설정할 수있는 곳은 어디입니까?

어렵지 않은 경우 코드를 작성하십시오.

답변

6

glReadPixels은 사용자가 제공하는 메모리 버퍼에 비트를 복사합니다. 수동으로 데이터를 원하는 형식의 이미지로 포맷하고 glReadPixels이 반환 된 후에 디스크에 기록해야합니다.

+0

메모리 버퍼를 디스크에 쓸 수있는 기능은 무엇입니까? – EthanHunt

+2

@EthanHunt :'fwrite'는 FILE *에 데이터를 쓰고,'fopen'은 지정한 파일 이름에 해당하는 FILE *을줍니다. 그러나 이미지 형식에 관한 부분을 무시하지 마십시오. 까다로운 부분입니다. –

+0

예제 코드를 줄 수 있습니까? – EthanHunt

2

파일에 해당 데이터를 저장하면 OpenGL에 해당 기능을 제공하지 않거나 제 3 자 라이브러리를 사용해야합니다.

Windows .bmp는 자신이 직접 작성하려고하는 경우 가장 쉽습니다. 위키 백과는 pretty good explanation of the file format입니다. 그렇지 않으면 저수준 제어를 위해 이미지 저장/로딩 라이브러리 libpng, libjpeg 등을 사용할 수 있습니다. 또는 devIL (다른 것들도 있지만 이것은 내가 좋아하는 것이며 GL과 잘 어울리는 매우 다재다능한 라이브러리입니다) 레벨 "그냥 해"이미지 I/O.

18

이 코드 조각은 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; 
+0

'glPixelStorei (GL_UNPACK_ALIGNMENT, 1);'은'glReadPixels' 전에 좋은 생각입니다 ([OpenGL Wiki] (http://www.opengl.org/wiki/GLAPI/glPixelStore)에서 더 읽으십시오) – Mortennobel

+0

사용하는 것이 현명합니까? '''BY_'' 대신''GL_UNSIGNED_BYTE''도 배열에 사용합니다. – Riot

+1

죄송합니다, 저는'''GLubyte''를 의미했습니다. – Riot

0

일반적으로 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(); 
3

의 Runnable 예를

당신이 창을 마우스로 클릭 할 때마다이하는 tmpX.ppm 파일은 현재 스크린 샷으로 작성됩니다.

Linux에서이 파일을 eog과 같이 볼 수 있으며 텍스트 편집기로 검사 할 수 있습니다.

이 창을 표시하지 않고 렌더링하려면 다음을 참조하십시오 How to use GLUT/OpenGL to render to a file?

#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.