Take the 2-minute tour ×

I try to save, through JNI, the output of the camera modified by OpenGL ES 2 on my tablet.

To achieve this, I use the libjpeg library compiled by the NDK-r8b.

I use the following code:

In the rendering function:

if (iIsPictureRequired)

The saving procedure:

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);
// Saves the pixel buffer
// 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);
   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_stdio_dest(&cinfo, l_file);
 cinfo.image_width      = iWidth;
 cinfo.image_height     = iHeight;
 cinfo.input_components = 3;
 cinfo.in_color_space   = JCS_RGB;

 // 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
l_res =true;
return l_res;


The display is correct but the generated JPEG seems tripled and overlap from left to right.

Scaled image (original size is 1210x648)

What did I do wrong ?

share|improve this question

1 Answer 1

up vote 0 down vote accepted

It appears that the internal format of the jpeg lib and the canvas do not match. Other appears to read/encode with RGBRGBRGB, other with RGBARGBARGBA.

You might be able to rearrange the image data, if everything else fails...

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

EDIT: now that the cause is verified, there might be even simpler modification. You might be able to get data from gl pixel buffer in the correct format:

 int l_size = iWidth*iHeight*3*sizeof(GLubyte);

And one more piece of warning: if this compiles, but the output is tilted, then it means that your screen width is not a multiple of 4, but that opengl wants to start each new row at dword boundary. But in that case there's a good opportunity of a crash, because in that case the l_size should have been 1,2 or 3 bytes larger than expected.

share|improve this answer
Using cinfo.input_components = 4;cinfo.in_color_space = JCS_RGBA_8888; leads to a crash in jpeg_set_defaults(&cinfo); –  Fabien R Nov 15 '12 at 14:59
Many thanks. Adding your code after glReadPixels(...) solved the problem. Is this solution specific to my tablet ? –  Fabien R Nov 16 '12 at 14:27
I don't think it's tablet specific. But anyway there should be some configuration in libjpeg that would accept a four byte format for three component image. –  Aki Suihkonen Nov 16 '12 at 14:37

Your Answer


