glReadpixels生成png,bmp文件

1.以当前时间,Y/M/D/H/M/S/MS命名

std::string generat_file_name(const std::string sufix) 
{
    time_t t;
    time(&t);
    struct tm *tmp_time = localtime(&t);
    char s[20];
	strftime(s, sizeof(s), "%04Y%02m%02d_%H-%M-%S-", tmp_time);

	struct timeval tpend;
	gettimeofday(&tpend,NULL);
	int secofday = (tpend.tv_sec + 3600 * 8 ) % 86400;
	int hours = secofday / 3600;
	int minutes = (secofday - hours * 3600 ) / 60;
	int seconds = secofday % 60;
	int milliseconds = tpend.tv_usec/1000;
	
	std::string img = std::string(s) + std::to_string(milliseconds) + sufix;

	return img;
}
const std::string pngSufix = ".png";
const std::string bmpSufix = ".bmp";

GLint m_iViewport[4];
glGetIntegerv(GL_VIEWPORT, m_iViewport);

2.将glReadPixels的buffer写入bmp 

void bmp_writer()
{
    GLubyte BMP_Header[BMP_Header_Length];
    #define BMP_Header_Length 54
    
    FILE*    pDummyFile;
    pDummyFile = fopen("dummy.bmp", "rb");
    if( pDummyFile == 0 )
        exit(0);
    fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);
    fclose(pDummyFile);

    FILE*    pWritingFile;
    GLubyte* pPixelData;
    GLint    i, j;
    GLint    PixelDataLength;

    // 计算像素数据的实际长度
    i = m_iViewport[2] * 4;   // 得到每一行的像素数据长度
    while( i%4 != 0 )      // 补充数据,直到i是的倍数
        ++i;               // 本来还有更快的算法,
                           // 但这里仅追求直观,对速度没有太高要求
    PixelDataLength = i * m_iViewport[3];

    // 分配内存和打开文件
    pPixelData = (GLubyte*)malloc(PixelDataLength);
    if( pPixelData == 0 )
        exit(0);

    std::string bmp = generat_file_name(bmpSufix);

    pWritingFile = fopen(bmp.c_str(), "wb");
    if( pWritingFile == 0 )
        exit(0);

    // 读取像素
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glReadPixels(0, 0, m_iViewport[2], m_iViewport[3], GL_RGB, GL_UNSIGNED_BYTE, pPixelData);

    // 把dummy.bmp的文件头复制为新文件的文件头
    fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);
    fseek(pWritingFile, 0x0012, SEEK_SET);
    i = m_iViewport[2];
    j = m_iViewport[3];
    fwrite(&i, sizeof(i), 1, pWritingFile);
    fwrite(&j, sizeof(j), 1, pWritingFile);

    // 写入像素数据
    fseek(pWritingFile, 0, SEEK_END);
    fwrite(pPixelData, PixelDataLength, 1, pWritingFile);

    // 释放内存和关闭文件
    fclose(pWritingFile);
    free(pPixelData);
}

2.将glReadPixels的buffer写入png

Reference:https://stackoverflow.com/questions/21853224/save-opengl-screen-pixels-to-png-using-libpng
 

void png_writer()
{
    uint8_t* pPixelData;
    GLint    i, j;
    GLint    PixelDataLength;

    // 计算像素数据的实际长度
    i = m_iViewport[2] * 4;   // 得到每一行的像素数据长度
    while( i%4 != 0 )      // 补充数据,直到i是的倍数
        ++i;               // 本来还有更快的算法,
                           // 但这里仅追求直观,对速度没有太高要求
    PixelDataLength = i * m_iViewport[3];

    // 分配内存和打开文件
    pPixelData = (uint8_t*)malloc(PixelDataLength);
    if( pPixelData == 0 )
        exit(0);

    // 读取像素
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glReadPixels(0, 0, m_iViewport[2], m_iViewport[3], GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)pPixelData);
    int w = m_iViewport[2], h = m_iViewport[3];
    for (int j = 0; j * 2 < h; ++j) {
        int x = j * w * 3;
        int y = (h - 1 - j) * w * 3;
        for (int i = w * 3; i > 0; --i) {
            std::swap(pPixelData[x], pPixelData[y]);
            ++x;
            ++y;
        }
    }

    std::string png = generat_file_name(pngSufix);
    bool ret = save_png_libpng(png.c_str(), pPixelData, w, h);
    if (ret)
       printf("Done\n");
    else
       printf("Failed\n");
}

bool save_png_libpng(const char *filename, uint8_t *pixels, int w, int h)
{
    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!png)
        return false;

    png_infop info = png_create_info_struct(png);
    if (!info) {
        png_destroy_write_struct(&png, &info);
        return false;
    }

    FILE *fp = fopen(filename, "wb");
    if (!fp) {
        png_destroy_write_struct(&png, &info);
        return false;
    }

    png_init_io(png, fp);
    png_set_IHDR(png, info, w, h, 8 /* depth */, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    png_colorp palette = (png_colorp)png_malloc(png, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
    if (!palette) {
        fclose(fp);
        png_destroy_write_struct(&png, &info);
        return false;
    }
    png_set_PLTE(png, info, palette, PNG_MAX_PALETTE_LENGTH);
    png_write_info(png, info);
    png_set_packing(png);

    png_bytepp rows = (png_bytepp)png_malloc(png, h * sizeof(png_bytep));
    for (int i = 0; i < h; ++i)
        rows[i] = (png_bytep)(pixels + (h - i - 1) * w * 3);

    png_write_image(png, rows);
    png_write_end(png, info);
    png_free(png, palette);
    png_destroy_write_struct(&png, &info);

    fclose(fp);
    delete[] rows;

    free(pixels);
    return true;
}

void png_writer(const char* filename, int w, int h)
{
    // 读取buffer: RGB565
    int32_t stride = 2;
    uint32_t bufferSize = w * h * stride;
    uint8_t* buffer = (uint8_t*)malloc(bufferSize);
    glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, buffer);

    // 保存png图片
    uint8_t* pixels = buffer;
    int32_t& nWidth = w;
    int32_t& nHeight = h;
    int32_t& nBitdepth = stride;
    int32_t nVerticalFlip = 1;
    int32_t RGB_BYTE = 4;

    int32_t i = 0;
    int32_t j = 0;
    int32_t nTemp = 0;
    int32_t nPos = 0;
    int32_t nRet = 0;

    png_byte color_type = PNG_COLOR_TYPE_RGBA;
    png_structp png_ptr;
    png_infop info_ptr;
    png_bytep * row_pointers = NULL;
    uint16_t* pixels_16 = (uint16_t*)pixels;
    FILE *fp = NULL;

    if (nBitdepth == 2)
    {
        RGB_BYTE = 3;
        color_type = PNG_COLOR_TYPE_RGB;
    }
    do
    {
        /* create file */
        fp = fopen(filename, ("wb"));
        if (fp == NULL)
        {
            nRet = 0;
            break;
        }

        /* initialize stuff */
        png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
        if (png_ptr == NULL)
        {
            nRet = 0;
            break;
        }

        info_ptr = png_create_info_struct(png_ptr);
        if (info_ptr == NULL)
        {
            nRet = 0;
            break;
        }

        if (setjmp(png_jmpbuf(png_ptr)))
        {
            nRet = 0;
            break;
        }
        png_init_io(png_ptr, (png_FILE_p)fp);

        /* write header */
        if (setjmp(png_jmpbuf(png_ptr)))
        {
            nRet = 0;
            break;
        }

        png_set_IHDR(png_ptr, info_ptr, nWidth, nHeight,
                     8, color_type, PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        png_write_info(png_ptr, info_ptr);

        /* write bytes */
        if (setjmp(png_jmpbuf(png_ptr)))
        {
            nRet = 0;
            break;
        }

        nTemp = RGB_BYTE * nWidth;
        row_pointers = (png_bytep*)malloc(nHeight * sizeof(png_bytep));
        if (row_pointers == NULL)
        {
            nRet = 0;
            break;
        }
        memset((void*)row_pointers, 0, nHeight * sizeof(png_bytep));
        int32_t nStart = 0;
        int32_t nAddValue = 1;
        if (nVerticalFlip > 0)
        {
            nStart = nHeight - 1;
            nAddValue = -1;
        }
        for(i = nStart; i >= 0 && i < nHeight; i+=nAddValue)
        {
            row_pointers[i] = (png_bytep)malloc(sizeof(uint8_t) * nTemp);
            if (row_pointers[i] == NULL)
            {
                nRet = 0;
                for (j = 0; j < i; j++)
                {
                    if (row_pointers[j] != NULL)
                    {
                        free(row_pointers[j]);
                        row_pointers[j] = NULL;
                    }
                }
                break;
            }
            memset((void*)row_pointers[i], 0, sizeof(uint8_t) * nTemp);
            if (nBitdepth == 2)
            {
                for(j = 0; j < nTemp; j += RGB_BYTE)
                {
                    uint16_t pixel = pixels_16[nPos++];
                    row_pointers[i][j + 2] = (pixel & 0x1f) << 3; /* blue */
                    row_pointers[i][j + 1] = (pixel & 0x7e0) >> 3; /* green */
                    row_pointers[i][j]   = (pixel & 0xf800) >> 8; /* red */
                }
            }
            else
            {
                for(j = 0; j < nTemp; j += RGB_BYTE)
                {
                    row_pointers[i][j + 0] = pixels[nPos++]; /* blue */
                    row_pointers[i][j + 1] = pixels[nPos++]; /* green */
                    row_pointers[i][j + 2] = pixels[nPos++]; /* red */
                    row_pointers[i][j + 3] = pixels[nPos++]; /* a */
                }
            }

        }
        png_write_image(png_ptr, row_pointers);

        /* end write */
        if (setjmp(png_jmpbuf(png_ptr)))
        {
            nRet = 0;
            break;
        }
        png_write_end(png_ptr, NULL);

        /* cleanup heap allocation */
        png_destroy_write_struct(&png_ptr, &info_ptr);
        if (row_pointers != NULL)
        {
            for (j = 0; j < nHeight; j++)
            {
                if (row_pointers[j] != NULL)
                {
                    free(row_pointers[j]);
                    row_pointers[j] = NULL;
                }
            }
            free(row_pointers);
            row_pointers = NULL;
        }
        nRet = 1;
    } while (0);

    if (fp != NULL) {
        fclose(fp);
        fp = NULL;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值