all_by_grace all_by_grace - 2 months ago 38
C++ Question

Need help in reading JPEG file using libjpeg

I followed the example code in the libjpeg example file, however I was not able to read the image data.

I have the following struct, and I created an instance of this struct.

struct ImageData {
unsigned char *pixels;
long width;
long height;
};

ImageData *imageData;


Below is my read_JPEG_file function:

int read_JPEG_file (char * filename)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;

/* More stuff */
FILE * infile; /* source file */
JSAMPARRAY buffer; /* Output row buffer */
int row_stride; /* physical row width in output buffer */

if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return 0;
}

/* Step 1: allocate and initialize JPEG decompression object */

/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(jerr.setjmp_buffer)) {

jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);

/* Step 2: specify data source (eg, a file) */

jpeg_stdio_src(&cinfo, infile);

/* Step 3: read file parameters with jpeg_read_header() */

(void) jpeg_read_header(&cinfo, TRUE);
/* Step 4: set parameters for decompression */

/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/

/* Step 5: Start decompressor */

(void) jpeg_start_decompress(&cinfo);


row_stride = cinfo.output_width * cinfo.output_components;
/* Make a one-row-high sample array that will go away when done with image */
buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

imageData = new ImageData;
imageData->width = cinfo.output_width;
imageData->height = cinfo.output_height;

imageData->pixels = new unsigned char [cinfo.output_width * cinfo.output_height * cinfo.output_components];
long counter = 0;

//step 6, read the image line by line
while (cinfo.output_scanline < cinfo.output_height) {
//IT ALWAYS crash ON THIS JPEG_READ_SCANLINES FUNCTION CALL BELOW
(void) jpeg_read_scanlines(&cinfo, (JSAMPARRAY)(imageData->pixels), 1);
counter +=row_stride;

}
/* Step 7: Finish decompression */

(void) jpeg_finish_decompress(&cinfo);
/* Step 8: Release JPEG decompression object */

/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);

fclose(infile);
/* And we're done! */
return 1;
}


It always fails on this JPEG_READ_SCANLINES function, in the step 6 above. I got an "EXC_BAD_ACCESS" signal on that line.

Does anyone have any idea, or have some working examples on reading .jpg file with libjpeg that you can share here? I have checked the size of my imageData->pixels, and compared it with the size of the jpeg file itself, and it has the same size. The memory for this variable has also dynamically allocated, so I know that it was not a memory problem.

Any ideas?

Answer

jpeg_read_scanlines function receives an array of pointers (not the direct pointer of pixels as imageData->pixels). So we should create a JSAMPARRAY first:

int buffer_height = 1;
JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW) * buffer_height);
buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);

In your code you've created a "buffer" with "cinfo.mem->alloc_sarray" but you never use it. The final step is to pass the "buffer" as argument of jpeg_read_scanlines:

while (cinfo.output_scanline < cinfo.output_height) {
  jpeg_read_scanlines(&cinfo, buffer, 1);
  memcpy(imageData->pixels+counter, buffer[0], row_stride);
  counter += row_stride;
}

See that we're using "imageData->pixels+counter", not just "imageData->pixels" as in your code. In this way we write each row after another in the whole "imageData->pixels" memory chunk.

Comments