Later I turn to use libjpeg-turbo although I really do not need to performance of SIMD instructions. Luckily libjpeg-turbo has a Visual Studio version of static library and I do to encounter the runtime error in libjpeg any more.
Basically my codes should be simply, as illustrated by the following pseudo-codes:
jpeg_create_decompress(); fopen(jpeg_file); jpeg_stdio_src(); jpeg_read_header(); jpeg_start_decompress(); while loop { jpeg_read_scanlines(); } jpeg_finish_decompress(); jpeg_destroy_decompress(); fclose();
However, to my surprise, libjpeg use a setjmp/longjmp approach to detect and handle the errors. Frankly speaking, although I have been using C languages for years, I really do not like the GOTO style of handling errors. The libjpeg is emulating an Object-oriented approach by allowing programmer to build an error hander to intercept the errors.
I am interested in two kinds of errors:
- Fatal errors: the library will quit in this case
- Warnings: the library can continue with data corruption
my_error_exit () { /* store the error code in the global variable */ /* store the error message in the global variable */ longjmp (myerr->setjmp_buffer, 1); /* Return control to the setjmp point */ } my_output_message () { /* store the error code in the global variable */ /* store the error message in the global variable */ }
The full source listing is as follows:
#include#include "stdafx.h" #include "jpeglib.h" #include #include int error_message_code; char error_message_buffer[JMSG_LENGTH_MAX]; struct my_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; typedef struct my_error_mgr * my_error_ptr; METHODDEF(void) my_error_exit (j_common_ptr cinfo) { my_error_ptr myerr = (my_error_ptr) cinfo->err; error_message_code = cinfo->err->msg_code; /* store the code in the global variable */ (*cinfo->err->format_message) (cinfo, error_message_buffer); /* store the message in the global variable */ printf ("Error intercepted in my_error_exit(): error_code = %d message = \'%s\'\n", error_message_code, error_message_buffer); longjmp(myerr->setjmp_buffer, 1); /* Return control to the setjmp point */ } METHODDEF(void) my_output_message (j_common_ptr cinfo) { error_message_code = cinfo->err->msg_code; (*cinfo->err->format_message) (cinfo, error_message_buffer); } int _tmain(int argc, _TCHAR* argv[]) { struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE * infile; JSAMPARRAY ptr; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); fclose(infile); return 0; } jpeg_create_decompress(&cinfo); if ((infile = fopen("C:\\bin\\libjpeg-turbo\\b.jpg", "rb")) == NULL) { printf("cannot open jpeg file"); return 1; } jpeg_stdio_src(&cinfo, infile); (void) jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; ptr = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1); while (cinfo.output_scanline < cinfo.output_height) { error_message_code = 0; jpeg_read_scanlines(&cinfo, (JSAMPARRAY) ptr, 1); if (error_message_code) printf("Error occured at scanline %d: Error code = %d message= \'%s\'\n", cinfo.output_scanline, error_message_code, error_message_buffer); } // while (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose (infile); return 0; }
Postscript
I prepare two corrupted jpeg files. The first is truncated file that the exact image height is smaller than that is specified in the jpeg header. In this case, I can successfully intercept the error at scanline 313 with Error code = 120 and error message = "Premature end of JPEG file". The second is truncated that even the jpeg header cannot be successfully read. In this case, my my_error_exit() terminating route can capture the error_code = 51 and error message = "JPEG datastream contains no image".