2012-11-14 52 views
1

我尝试通过JNI在平板电脑上保存由OpenGL ES 2修改的相机输出。将SurfaceTexture保存为JPEG

为了达到这个目的,我使用了由NDK-r8b编译的libjpeg库。

我使用以下代码:

在绘制功能:

renderImage(); 
if (iIsPictureRequired) 
{ 
    savePicture(); 
    iIsPictureRequired=false; 
} 

的保存过程:

bool Image::savePicture() 
{ 
bool l_res =false; 
char p_filename[]={"/sdcard/Pictures/testPic.jpg"}; 
// Allocates the image buffer (RGBA) 
int l_size = iWidth*iHeight*4*sizeof(GLubyte); 
GLubyte *l_image = (GLubyte*)malloc(l_size); 
if (l_image==NULL) 
{ 
    LOGE("Image::savePicture:could not allocate %d bytes",l_size); 
    return l_res; 
} 
// Reads pixels from the color buffer (byte-aligned) 
glPixelStorei(GL_PACK_ALIGNMENT, 1); 
checkGlError("glPixelStorei"); 
// Saves the pixel buffer 
glReadPixels(0,0,iWidth,iHeight,GL_RGBA,GL_UNSIGNED_BYTE,l_image); 
checkGlError("glReadPixels"); 
// Stores the file 
FILE* l_file = fopen(p_filename, "wb"); 
if (l_file==NULL) 
{ 
    LOGE("Image::savePicture:could not create %s:errno=%d",p_filename,errno); 
    free(l_image); 
    return l_res; 
} 
// JPEG structures 
struct jpeg_compress_struct cinfo; 
struct jpeg_error_mgr  jerr; 

cinfo.err = jpeg_std_error(&jerr); 
jerr.trace_level = 10; 

jpeg_create_compress(&cinfo); 
jpeg_stdio_dest(&cinfo, l_file); 
cinfo.image_width  = iWidth; 
cinfo.image_height  = iHeight; 
cinfo.input_components = 3; 
cinfo.in_color_space = JCS_RGB; 
jpeg_set_defaults(&cinfo); 

// Image quality [0..100] 
jpeg_set_quality (&cinfo, 70, true); 
jpeg_start_compress(&cinfo, true); 

// Saves the buffer 
JSAMPROW row_pointer[1];   // pointer to a single row 

// JPEG stores the image from top to bottom (OpenGL does the opposite) 
while (cinfo.next_scanline < cinfo.image_height) 
{ 
    row_pointer[0] = (JSAMPROW)&l_image[(cinfo.image_height-1-cinfo.next_scanline)* (cinfo.input_components)*iWidth]; 
    jpeg_write_scanlines(&cinfo, row_pointer, 1); 
} 
// End of the process 
jpeg_finish_compress(&cinfo); 
fclose(l_file); 
free(l_image); 
l_res =true; 
return l_res; 

} 

的显示是正确的,但所生成的JPEG似乎三倍,从重叠左到右。

Scaled image (original size is 1210x648)

我做了什么错?

回答

0

看来,jpeg库的内部格式和画布不匹配。其他似乎读取/编码RGBRGBRGB,其他与RGBARGBARGBA。

您可能能够重新排列的图像数据,如果一切都失败了......

char *dst_ptr = l_image; char *src_ptr = l_image; 
for (i=0;i<width*height;i++) { *dst_ptr++=*src_ptr++; 
    *dst_ptr++=*src_ptr++; *dst_ptr++=*src_ptr++; src_ptr++; } 

编辑:现在的原因被证实,可能有更简单的修改。 您可能能够以正确的格式,以获得从GL像素缓冲数据:

int l_size = iWidth*iHeight*3*sizeof(GLubyte); 
... 
glReadPixels(0,0,iWidth,iHeight,GL_RGB,GL_UNSIGNED_BYTE,l_image); 

还有一一块警告:如果编译,但输出倾斜,那么就意味着你的屏幕宽度不是4的倍数,但是opengl想要在dword边界开始每个新行。但在这种情况下,出现崩溃的可能性很大,因为在这种情况下,l_size应该比预期的长1,2或3个字节。

+0

使用'cinfo.input_components = 4; cinfo.in_color_space = JCS_RGBA_8888;'导致'jpeg_set_defaults(&cinfo)崩溃;' –

+0

非常感谢。在glReadPixels(...)之后添加你的代码解决了这个问题。这种解决方案是特定于我的平板电脑吗 –

+0

我不认为它是平板电脑特定的。但无论如何,在libjpeg中应该有一些配置可以接受三个组件映像的四字节格式。 –