SDL_SaveBMP saves images upside down

后端 未结 1 1264
孤街浪徒
孤街浪徒 2021-01-17 05:51

I have used SDL to save the window image via SDL_SaveBMP. The problem is that the saved image is upside down.

The saved image is

<

1条回答
  •  迷失自我
    2021-01-17 06:22

    After a lot of struggles, I have found the solutions and I share it for programmers who will have the same problem in future.

    The solution is here.

    #include "SDL/SDL.h"
    #include 
    #include 
    #include 
    
    #define SDL_LOCKIFMUST(s) (SDL_MUSTLOCK(s) ? SDL_LockSurface(s) : 0)
    #define SDL_UNLOCKIFMUST(s) { if(SDL_MUSTLOCK(s)) SDL_UnlockSurface(s); }
    
    int invert_surface_vertical(SDL_Surface *surface)
    {
        Uint8 *t;
        register Uint8 *a, *b;
        Uint8 *last;
        register Uint16 pitch;
    
        if( SDL_LOCKIFMUST(surface) < 0 )
            return -2;
    
        /* do nothing unless at least two lines */
        if(surface->h < 2) {
            SDL_UNLOCKIFMUST(surface);
            return 0;
        }
    
        /* get a place to store a line */
        pitch = surface->pitch;
        t = (Uint8*)malloc(pitch);
    
        if(t == NULL) {
            SDL_UNLOCKIFMUST(surface);
            return -2;
        }
    
        /* get first line; it's about to be trampled */
        memcpy(t,surface->pixels,pitch);
    
        /* now, shuffle the rest so it's almost correct */
        a = (Uint8*)surface->pixels;
        last = a + pitch * (surface->h - 1);
        b = last;
    
        while(a < b) {
            memcpy(a,b,pitch);
            a += pitch;
            memcpy(b,a,pitch);
            b -= pitch;
        }
    
        /* in this shuffled state, the bottom slice is too far down */
        memmove( b, b+pitch, last-b );
    
        /* now we can put back that first row--in the last place */
        memcpy(last,t,pitch);
    
        /* everything is in the right place; close up. */
        free(t);
        SDL_UNLOCKIFMUST(surface);
    
        return 0;
    }
    
    void screen_shot(std::string filename)
    {
        int width = glutGet(GLUT_WINDOW_WIDTH);
        int height = glutGet(GLUT_WINDOW_HEIGHT);
    
        SDL_Surface * image = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
    
        glReadBuffer(GL_FRONT);
        glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, image->pixels);
    
        invert_surface_vertical(image);
        SDL_SaveBMP(image, filename.c_str());
        SDL_FreeSurface(image);
    }
    
    void cback_render()
    {
        if(!glutGetWindow())
            return ;
        static float rotations = 0;
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    
        glLoadIdentity();
        glRotatef(rotations, 0, 0, 1);
    
        glBegin(GL_TRIANGLES);
            glVertex3f(0,0,0);
            glVertex3f(1,0,0);
            glVertex3f(0,1,0);
        glEnd();
    
        glutSwapBuffers();
    }
    
    void timer(int )
    {
        if(!glutGetWindow())
            return ;
        static bool saved=false;
        if(!saved)
        {
            screen_shot("image.bmp");
            saved=true;
        }
        glutPostRedisplay();
        glutMainLoopEvent();
        glutTimerFunc(30, timer, 1);
    }
    
    void init()
    {
        int argc=1;
        glutInit(&argc, NULL);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
        glutInitWindowPosition(100, 100);
        glutInitWindowSize(512, 512);
        glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
    
        glutCreateWindow("freegluttest");
        glutDisplayFunc (cback_render);
        glutTimerFunc(30, timer, 1);
    }
    
    int main()
    {
        init();
        glutMainLoop();
    
        return 0;
    }
    

    build:

    g++ main.cpp -o main -lGL -lglut -lSDL -lSDL2
    

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