我正在尝试使用 libjpeg 从 opengl 缓冲区保存屏幕截图。
我使用的功能是这个
void OnKeyPress(unsigned char key, int x, int y) {
if (key != static_cast<unsigned char>('p'))
return;
int width = g_current_width;
int height = g_current_height;
boost::scoped_array<boost::uint8_t> buffer(new boost::uint8_t[3 * width * height]);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE,
reinterpret_cast<GLvoid *>(buffer.get()));
glReadBuffer(GL_BACK);
FlipImage(buffer.get(), width, height);
// Generate a BMP files for testing purposes
SaveRGB("screenshot.bmp", buffer.get(), width, height);
boost::shared_ptr<FILE> outfile(fopen("screenshot.jpeg", "wb"), fclose);
if (!outfile)
return;
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jerr.trace_level = 10;
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile.get());
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 100, true);
jpeg_start_compress(&cinfo, true);
int row_stride = width * 3;
JSAMPROW row_pointer[1];
int counter = 0;
std::cout << boost::format("height: %d\n") % height;
boost::uint8_t *r_buffer = buffer.get();
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &r_buffer[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_pointer, 1);
std::cout << boost::format("current line: %d\n") % (counter++);
}
jpeg_finish_compress(&cinfo); // never reaches this point
outfile.reset();
jpeg_destroy_compress(&cinfo);
}
此函数启动,但经过一些迭代(大约 100 – 150 次)后,该函数返回时不会在文件中写入任何内容,也不会生成警告或错误。
如果我使用内存编码(这实际上是我需要的),函数完成,但结果没有意义。此外,任何释放缓冲区的尝试都会出错。这是内存目标版本
void OnKeyPress(unsigned char key, int x, int y) {
if (key != static_cast<unsigned char>('p'))
return;
int width = g_current_width;
int height = g_current_height;
boost::scoped_array<boost::uint8_t> buffer(new boost::uint8_t[3 * width * height]);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE,
reinterpret_cast<GLvoid *>(buffer.get()));
glReadBuffer(GL_BACK);
FlipImage(buffer.get(), width, height);
// Generate a BMP files for testing purposes
SaveRGB("screenshot.bmp", buffer.get(), width, height);
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jerr.trace_level = 10;
jpeg_create_compress(&cinfo);
boost::uint8_t *jpeg_buffer_raw = NULL;
unsigned long outbuffer_size = 0;
jpeg_mem_dest(&cinfo, &jpeg_buffer_raw, &outbuffer_size);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 100, true);
jpeg_start_compress(&cinfo, true);
int row_stride = width * 3;
JSAMPROW row_pointer[1];
int counter = 0;
std::cout << boost::format("height: %d\n") % height;
boost::uint8_t *r_buffer = buffer.get();
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &r_buffer[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_pointer, 1);
std::cout << boost::format("current line: %d\n") % (counter++);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
std::ofstream jpegfile("screenshot.jpg");
jpegfile.write(reinterpret_cast<const char*>(jpeg_buffer_raw), outbuffer_size);
jpegfile.flush();
// calling free(jpeg_buffer_raw); or delete[] jpeg_buffer_raw; generates an error
}
此函数生成以下 jpeg 图像:
相比之下,保存位图文件的行会生成这个: