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;
}
}