The Independent JPEG Group's JPEG software v5
diff --git a/example.c b/example.c index 666dd6f..cb8c64a 100644 --- a/example.c +++ b/example.c
@@ -1,31 +1,29 @@ /* * example.c * - * This file is not actually part of the JPEG software. Rather, it provides - * a skeleton that may be useful for constructing applications that use the - * JPEG software as subroutines. This code will NOT do anything useful as is. + * This file illustrates how to use the IJG code as a subroutine library + * to read or write JPEG image files. You should look at this code in + * conjunction with the documentation file libjpeg.doc. * - * This file illustrates how to use the JPEG code as a subroutine library - * to read or write JPEG image files. We assume here that you are not - * merely interested in converting the image to yet another image file format - * (if you are, you should be adding another I/O module to cjpeg/djpeg, not - * constructing a new application). Instead, we show how to pass the - * decompressed image data into or out of routines that you provide. For - * example, a viewer program might use the JPEG decompressor together with - * routines that write the decompressed image directly to a display. + * This code will not do anything useful as-is, but it may be helpful as a + * skeleton for constructing routines that call the JPEG library. * * We present these routines in the same coding style used in the JPEG code * (ANSI function definitions, etc); but you are of course free to code your * routines in a different style if you prefer. */ +#include <stdio.h> + /* - * Include file for declaring JPEG data structures. - * This file also includes some system headers like <stdio.h>; - * if you prefer, you can include "jconfig.h" and "jpegdata.h" instead. + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". */ -#include "jinclude.h" +#include "jpeglib.h" /* * <setjmp.h> is used for the optional error recovery mechanism shown in @@ -45,587 +43,375 @@ /* - * To supply the image data for compression, you must define three routines - * input_init, get_input_row, and input_term. These routines will be called - * from the JPEG compressor via function pointer values that you store in the - * cinfo data structure; hence they need not be globally visible and the exact - * names don't matter. (In fact, the "METHODDEF" macro expands to "static" if - * you use the unmodified JPEG include files.) + * IMAGE DATA FORMATS: * - * The input file reading modules (jrdppm.c, jrdgif.c, jrdtarga.c, etc) may be - * useful examples of what these routines should actually do, although each of - * them is encrusted with a lot of specialized code for its own file format. + * The standard input image format is a rectangular array of pixels, with + * each pixel having the same number of "component" values (color channels). + * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars). + * If you are working with color data, then the color values for each pixel + * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit + * RGB color. + * + * For this example, we'll assume that this data structure matches the way + * our application has stored the image in memory, so we can just pass a + * pointer to our image buffer. In particular, let's say that the image is + * RGB color and is described by: */ - -METHODDEF void -input_init (compress_info_ptr cinfo) -/* Initialize for input; return image size and component data. */ -{ - /* This routine must return five pieces of information about the incoming - * image, and must do any setup needed for the get_input_row routine. - * The image information is returned in fields of the cinfo struct. - * (If you don't care about modularity, you could initialize these fields - * in the main JPEG calling routine, and make this routine be a no-op.) - * We show some example values here. - */ - cinfo->image_width = 640; /* width in pixels */ - cinfo->image_height = 480; /* height in pixels */ - /* JPEG views an image as being a rectangular array of pixels, with each - * pixel having the same number of "component" values (color channels). - * You must specify how many components there are and the colorspace - * interpretation of the components. Most applications will use RGB data or - * grayscale data. If you want to use something else, you'll need to study - * and perhaps modify jcdeflts.c, jccolor.c, and jdcolor.c. - */ - cinfo->input_components = 3; /* or 1 for grayscale */ - cinfo->in_color_space = CS_RGB; /* or CS_GRAYSCALE for grayscale */ - cinfo->data_precision = 8; /* bits per pixel component value */ - /* In the current JPEG software, data_precision must be set equal to - * BITS_IN_JSAMPLE, which is 8 unless you twiddle jconfig.h. Future - * versions might allow you to say either 8 or 12 if compiled with - * 12-bit JSAMPLEs, or up to 16 in lossless mode. In any case, - * it is up to you to scale incoming pixel values to the range - * 0 .. (1<<data_precision)-1. - * If your image data format is fixed at a byte per component, - * then saying "8" is probably the best long-term solution. - */ -} +extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ +extern int image_height; /* Number of rows in image */ +extern int image_width; /* Number of columns in image */ /* - * This function is called repeatedly and must supply the next row of pixels - * on each call. The rows MUST be returned in top-to-bottom order if you want - * your JPEG files to be compatible with everyone else's. (If you cannot - * readily read your data in that order, you'll need an intermediate array to - * hold the image. See jrdtarga.c or jrdrle.c for examples of handling - * bottom-to-top source data using the JPEG code's portable mechanisms.) - * The data is to be returned into a 2-D array of JSAMPLEs, indexed as - * JSAMPLE pixel_row[component][column] - * where component runs from 0 to cinfo->input_components-1, and column runs - * from 0 to cinfo->image_width-1 (column 0 is left edge of image). Note that - * this is actually an array of pointers to arrays rather than a true 2D array, - * since C does not support variable-size multidimensional arrays. - * JSAMPLE is typically typedef'd as "unsigned char". - */ - - -METHODDEF void -get_input_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) -/* Read next row of pixels into pixel_row[][] */ -{ - /* This example shows how you might read RGB data (3 components) - * from an input file in which the data is stored 3 bytes per pixel - * in left-to-right, top-to-bottom order. - */ - register FILE * infile = cinfo->input_file; - register JSAMPROW ptr0, ptr1, ptr2; - register long col; - - ptr0 = pixel_row[0]; - ptr1 = pixel_row[1]; - ptr2 = pixel_row[2]; - for (col = 0; col < cinfo->image_width; col++) { - *ptr0++ = (JSAMPLE) getc(infile); /* red */ - *ptr1++ = (JSAMPLE) getc(infile); /* green */ - *ptr2++ = (JSAMPLE) getc(infile); /* blue */ - } -} - - -METHODDEF void -input_term (compress_info_ptr cinfo) -/* Finish up at the end of the input */ -{ - /* This termination routine will very often have no work to do, */ - /* but you must provide it anyway. */ - /* Note that the JPEG code will only call it during successful exit; */ - /* if you want it called during error exit, you gotta do that yourself. */ -} - - -/* - * That's it for the routines that deal with reading the input image data. - * Now we have overall control and parameter selection routines. - */ - - -/* - * This routine must determine what output JPEG file format is to be written, - * and make any other compression parameter changes that are desirable. - * This routine gets control after the input file header has been read - * (i.e., right after input_init has been called). You could combine its - * functions into input_init, or even into the main control routine, but - * if you have several different input_init routines, it's a definite win - * to keep this separate. You MUST supply this routine even if it's a no-op. - */ - -METHODDEF void -c_ui_method_selection (compress_info_ptr cinfo) -{ - /* If the input is gray scale, generate a monochrome JPEG file. */ - if (cinfo->in_color_space == CS_GRAYSCALE) - j_monochrome_default(cinfo); - /* For now, always select JFIF output format. */ - jselwjfif(cinfo); -} - - -/* - * OK, here is the main function that actually causes everything to happen. - * We assume here that the target filename is supplied by the caller of this - * routine, and that all JPEG compression parameters can be default values. + * Sample routine for JPEG compression. We assume that the target file name + * and a compression quality factor are passed in. */ GLOBAL void -write_JPEG_file (char * filename) +write_JPEG_file (char * filename, int quality) { - /* These three structs contain JPEG parameters and working data. - * They must survive for the duration of parameter setup and one - * call to jpeg_compress; typically, making them local data in the - * calling routine is the best strategy. + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". */ - struct Compress_info_struct cinfo; - struct Compress_methods_struct c_methods; - struct External_methods_struct e_methods; + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ - /* Initialize the system-dependent method pointers. */ - cinfo.methods = &c_methods; /* links to method structs */ - cinfo.emethods = &e_methods; - /* Here we use the default JPEG error handler, which will just print - * an error message on stderr and call exit(). See the second half of - * this file for an example of more graceful error recovery. - */ - jselerror(&e_methods); /* select std error/trace message routines */ - /* Here we use the standard memory manager provided with the JPEG code. - * In some cases you might want to replace the memory manager, or at - * least the system-dependent part of it, with your own code. - */ - jselmemmgr(&e_methods); /* select std memory allocation routines */ - /* If the compressor requires full-image buffers (for entropy-coding - * optimization or a noninterleaved JPEG file), it will create temporary - * files for anything that doesn't fit within the maximum-memory setting. - * (Note that temp files are NOT needed if you use the default parameters.) - * You can change the default maximum-memory setting by changing - * e_methods.max_memory_to_use after jselmemmgr returns. - * On some systems you may also need to set up a signal handler to - * ensure that temporary files are deleted if the program is interrupted. - * (This is most important if you are on MS-DOS and use the jmemdos.c - * memory manager back end; it will try to grab extended memory for - * temp files, and that space will NOT be freed automatically.) - * See jcmain.c or jdmain.c for an example signal handler. - */ + /* Step 1: allocate and initialize JPEG compression object */ - /* Here, set up pointers to your own routines for input data handling - * and post-init parameter selection. + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. */ - c_methods.input_init = input_init; - c_methods.get_input_row = get_input_row; - c_methods.input_term = input_term; - c_methods.c_ui_method_selection = c_ui_method_selection; + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); - /* Set up default JPEG parameters in the cinfo data structure. */ - j_c_defaults(&cinfo, 75, FALSE); - /* Note: 75 is the recommended default quality level; you may instead pass - * a user-specified quality level. Be aware that values below 25 will cause - * non-baseline JPEG files to be created (and a warning message to that - * effect to be emitted on stderr). This won't bother our decoder, but some - * commercial JPEG implementations may choke on non-baseline JPEG files. - * If you want to force baseline compatibility, pass TRUE instead of FALSE. - * (If non-baseline files are fine, but you could do without that warning - * message, set e_methods.trace_level to -1.) - */ + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ - /* At this point you can modify the default parameters set by j_c_defaults - * as needed. For a minimal implementation, you shouldn't need to change - * anything. See jcmain.c for some examples of what you might change. - */ - - /* Select the input and output files. - * Note that cinfo.input_file is only used if your input reading routines - * use it; otherwise, you can just make it NULL. + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ - - cinfo.input_file = NULL; /* if no actual input file involved */ - - if ((cinfo.output_file = fopen(filename, "wb")) == NULL) { + if ((outfile = fopen(filename, "wb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); exit(1); } + jpeg_stdio_dest(&cinfo, outfile); - /* Here we go! */ - jpeg_compress(&cinfo); + /* Step 3: set parameters for compression */ - /* That's it, son. Nothin' else to do, except close files. */ - /* Here we assume only the output file need be closed. */ - fclose(cinfo.output_file); - - /* Note: if you want to compress more than one image, we recommend you - * repeat this whole routine. You MUST repeat the j_c_defaults()/alter - * parameters/jpeg_compress() sequence, as some data structures allocated - * in j_c_defaults are freed upon exit from jpeg_compress. + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ } +/* + * SOME FINE POINTS: + * + * In the above loop, we ignored the return value of jpeg_write_scanlines, + * which is the number of scanlines actually written. We could get away + * with this because we were only relying on the value of cinfo.next_scanline, + * which will be incremented correctly. If you maintain additional loop + * variables then you should be careful to increment them properly. + * Actually, for output to a stdio stream you needn't worry, because + * then jpeg_write_scanlines will write all the lines passed (or else exit + * with a fatal error). Partial writes can only occur if you use a data + * destination module that can demand suspension of the compressor. + * (If you don't know what that's for, you don't need it.) + * + * If the compressor requires full-image buffers (for entropy-coding + * optimization or a noninterleaved JPEG file), it will create temporary + * files for anything that doesn't fit within the maximum-memory setting. + * (Note that temp files are NOT needed if you use the default parameters.) + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + * + * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG + * files to be compatible with everyone else's. If you cannot readily read + * your data in that order, you'll need an intermediate array to hold the + * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top + * source data using the JPEG code's internal virtual-array mechanisms. + */ + + /******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/ /* This half of the example shows how to read data from the JPEG decompressor. - * It's a little more refined than the above in that we show how to do your - * own error recovery. If you don't care about that, you don't need these - * next two routines. - */ - - -/* - * These routines replace the default trace/error routines included with the - * JPEG code. The example trace_message routine shown here is actually the - * same as the standard one, but you could modify it if you don't want messages - * sent to stderr. The example error_exit routine is set up to return - * control to read_JPEG_file() rather than calling exit(). You can use the - * same routines for both compression and decompression error recovery. - */ - -/* These static variables are needed by the error routines. */ -static jmp_buf setjmp_buffer; /* for return to caller */ -static external_methods_ptr emethods; /* needed for access to message_parm */ - - -/* This routine is used for any and all trace, debug, or error printouts - * from the JPEG code. The parameter is a printf format string; up to 8 - * integer data values for the format string have been stored in the - * message_parm[] field of the external_methods struct. - */ - -METHODDEF void -trace_message (const char *msgtext) -{ - fprintf(stderr, msgtext, - emethods->message_parm[0], emethods->message_parm[1], - emethods->message_parm[2], emethods->message_parm[3], - emethods->message_parm[4], emethods->message_parm[5], - emethods->message_parm[6], emethods->message_parm[7]); - fprintf(stderr, "\n"); /* there is no \n in the format string! */ -} - -/* - * The error_exit() routine should not return to its caller. The default - * routine calls exit(), but here we assume that we want to return to - * read_JPEG_file, which has set up a setjmp context for the purpose. - * You should make sure that the free_all method is called, either within - * error_exit or after the return to the outer-level routine. - */ - -METHODDEF void -error_exit (const char *msgtext) -{ - trace_message(msgtext); /* report the error message */ - (*emethods->free_all) (); /* clean up memory allocation & temp files */ - longjmp(setjmp_buffer, 1); /* return control to outer routine */ -} - - - -/* - * To accept the image data from decompression, you must define four routines - * output_init, put_color_map, put_pixel_rows, and output_term. + * It's a bit more refined than the above, in that we show: + * (a) how to modify the JPEG library's standard error-reporting behavior; + * (b) how to allocate workspace using the library's memory manager. * - * You must understand the distinction between full color output mode - * (N independent color components) and colormapped output mode (a single - * output component representing an index into a color map). You should use - * colormapped mode to write to a colormapped display screen or output file. - * Colormapped mode is also useful for reducing grayscale output to a small - * number of gray levels: when using the 1-pass quantizer on grayscale data, - * the colormap entries will be evenly spaced from 0 to MAX_JSAMPLE, so you - * can regard the indexes as directly representing gray levels at reduced - * precision. In any other case, you should not depend on the colormap - * entries having any particular order. - * To get colormapped output, set cinfo->quantize_colors to TRUE and set - * cinfo->desired_number_of_colors to the maximum number of entries in the - * colormap. This can be done either in your main routine or in - * d_ui_method_selection. For grayscale quantization, also set - * cinfo->two_pass_quantize to FALSE to ensure the 1-pass quantizer is used - * (presently this is the default, but it may not be so in the future). - * - * The output file writing modules (jwrppm.c, jwrgif.c, jwrtarga.c, etc) may be - * useful examples of what these routines should actually do, although each of - * them is encrusted with a lot of specialized code for its own file format. - */ - - -METHODDEF void -output_init (decompress_info_ptr cinfo) -/* This routine should do any setup required */ -{ - /* This routine can initialize for output based on the data passed in cinfo. - * Useful fields include: - * image_width, image_height Pretty obvious, I hope. - * data_precision bits per pixel value; typically 8. - * out_color_space output colorspace previously requested - * color_out_comps number of color components in same - * final_out_comps number of components actually output - * final_out_comps is 1 if quantize_colors is true, else it is equal to - * color_out_comps. - * - * If you have requested color quantization, the colormap is NOT yet set. - * You may wish to defer output initialization until put_color_map is called. - */ -} - - -/* - * This routine is called if and only if you have set cinfo->quantize_colors - * to TRUE. It is given the selected colormap and can complete any required - * initialization. This call will occur after output_init and before any - * calls to put_pixel_rows. Note that the colormap pointer is also placed - * in a cinfo field, whence it can be used by put_pixel_rows or output_term. - * num_colors will be less than or equal to desired_number_of_colors. - * - * The colormap data is supplied as a 2-D array of JSAMPLEs, indexed as - * JSAMPLE colormap[component][indexvalue] - * where component runs from 0 to cinfo->color_out_comps-1, and indexvalue - * runs from 0 to num_colors-1. Note that this is actually an array of - * pointers to arrays rather than a true 2D array, since C does not support - * variable-size multidimensional arrays. - * JSAMPLE is typically typedef'd as "unsigned char". If you want your code - * to be as portable as the JPEG code proper, you should always access JSAMPLE - * values with the GETJSAMPLE() macro, which will do the right thing if the - * machine has only signed chars. - */ - -METHODDEF void -put_color_map (decompress_info_ptr cinfo, int num_colors, JSAMPARRAY colormap) -/* Write the color map */ -{ - /* You need not provide this routine if you always set cinfo->quantize_colors - * FALSE; but a safer practice is to provide it and have it just print an - * error message, like this: - */ - fprintf(stderr, "put_color_map called: there's a bug here somewhere!\n"); -} - - -/* - * This function is called repeatedly, with a few more rows of pixels supplied - * on each call. With the current JPEG code, some multiple of 8 rows will be - * passed on each call except the last, but it is extremely bad form to depend - * on this. You CAN assume num_rows > 0. - * The data is supplied in top-to-bottom row order (the standard order within - * a JPEG file). If you cannot readily use the data in that order, you'll - * need an intermediate array to hold the image. See jwrrle.c for an example - * of outputting data in bottom-to-top order. - * - * The data is supplied as a 3-D array of JSAMPLEs, indexed as - * JSAMPLE pixel_data[component][row][column] - * where component runs from 0 to cinfo->final_out_comps-1, row runs from 0 to - * num_rows-1, and column runs from 0 to cinfo->image_width-1 (column 0 is - * left edge of image). Note that this is actually an array of pointers to - * pointers to arrays rather than a true 3D array, since C does not support - * variable-size multidimensional arrays. - * JSAMPLE is typically typedef'd as "unsigned char". If you want your code - * to be as portable as the JPEG code proper, you should always access JSAMPLE - * values with the GETJSAMPLE() macro, which will do the right thing if the - * machine has only signed chars. - * - * If quantize_colors is true, then there is only one component, and its values - * are indexes into the previously supplied colormap. Otherwise the values - * are actual data in your selected output colorspace. - */ - - -METHODDEF void -put_pixel_rows (decompress_info_ptr cinfo, int num_rows, JSAMPIMAGE pixel_data) -/* Write some rows of output data */ -{ - /* This example shows how you might write full-color RGB data (3 components) - * to an output file in which the data is stored 3 bytes per pixel. - */ - register FILE * outfile = cinfo->output_file; - register JSAMPROW ptr0, ptr1, ptr2; - register long col; - register int row; - - for (row = 0; row < num_rows; row++) { - ptr0 = pixel_data[0][row]; - ptr1 = pixel_data[1][row]; - ptr2 = pixel_data[2][row]; - for (col = 0; col < cinfo->image_width; col++) { - putc(GETJSAMPLE(*ptr0), outfile); /* red */ - ptr0++; - putc(GETJSAMPLE(*ptr1), outfile); /* green */ - ptr1++; - putc(GETJSAMPLE(*ptr2), outfile); /* blue */ - ptr2++; - } - } -} - - -METHODDEF void -output_term (decompress_info_ptr cinfo) -/* Finish up at the end of the output */ -{ - /* This termination routine may not need to do anything. */ - /* Note that the JPEG code will only call it during successful exit; */ - /* if you want it called during error exit, you gotta do that yourself. */ -} - - -/* - * That's it for the routines that deal with writing the output image. - * Now we have overall control and parameter selection routines. + * Just to make this example a little different from the first one, we'll + * assume that we do not intend to put the whole image into an in-memory + * buffer, but to send it line-by-line someplace else. We need a one- + * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG + * memory manager allocate it for us. This approach is actually quite useful + * because we don't need to remember to deallocate the buffer separately: it + * will go away automatically when the JPEG object is cleaned up. */ /* - * This routine gets control after the JPEG file header has been read; - * at this point the image size and colorspace are known. - * The routine must determine what output routines are to be used, and make - * any decompression parameter changes that are desirable. For example, - * if it is found that the JPEG file is grayscale, you might want to do - * things differently than if it is color. You can also delay setting - * quantize_colors and associated options until this point. + * ERROR HANDLING: * - * j_d_defaults initializes out_color_space to CS_RGB. If you want grayscale - * output you should set out_color_space to CS_GRAYSCALE. Note that you can - * force grayscale output from a color JPEG file (though not vice versa). + * The JPEG library's standard error handler (jerror.c) is divided into + * several "methods" which you can override individually. This lets you + * adjust the behavior without duplicating a lot of code, which you might + * have to update with each future release. + * + * Our example here shows how to override the "error_exit" method so that + * control is returned to the library's caller when a fatal error occurs, + * rather than calling exit() as the standard error_exit method does. + * + * We use C's setjmp/longjmp facility to return control. This means that the + * routine which calls the JPEG library must first execute a setjmp() call to + * establish the return point. We want the replacement error_exit to do a + * longjmp(). But we need to make the setjmp buffer accessible to the + * error_exit routine. To do this, we make a private extension of the + * standard JPEG error handler object. (If we were using C++, we'd say we + * were making a subclass of the regular error handler.) + * + * Here's the extended error handler struct: + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: */ METHODDEF void -d_ui_method_selection (decompress_info_ptr cinfo) +my_error_exit (j_common_ptr cinfo) { - /* if grayscale input, force grayscale output; */ - /* else leave the output colorspace as set by main routine. */ - if (cinfo->jpeg_color_space == CS_GRAYSCALE) - cinfo->out_color_space = CS_GRAYSCALE; + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; - /* select output routines */ - cinfo->methods->output_init = output_init; - cinfo->methods->put_color_map = put_color_map; - cinfo->methods->put_pixel_rows = put_pixel_rows; - cinfo->methods->output_term = output_term; + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); } /* - * OK, here is the main function that actually causes everything to happen. - * We assume here that the JPEG filename is supplied by the caller of this - * routine, and that all decompression parameters can be default values. - * The routine returns 1 if successful, 0 if not. + * Sample routine for JPEG decompression. We assume that the source file name + * is passed in. We want to return 1 on success, 0 on error. */ + GLOBAL int read_JPEG_file (char * filename) { - /* These three structs contain JPEG parameters and working data. - * They must survive for the duration of parameter setup and one - * call to jpeg_decompress; typically, making them local data in the - * calling routine is the best strategy. + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). */ - struct Decompress_info_struct cinfo; - struct Decompress_methods_struct dc_methods; - struct External_methods_struct e_methods; + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. */ + 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 */ - /* Select the input and output files. - * In this example we want to open the input file before doing anything else, + /* In this example we want to open the input file before doing anything else, * so that the setjmp() error recovery below can assume the file is open. - * Note that cinfo.output_file is only used if your output handling routines - * use it; otherwise, you can just make it NULL. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to read binary files. */ - if ((cinfo.input_file = fopen(filename, "rb")) == NULL) { + if ((infile = fopen(filename, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); return 0; } - cinfo.output_file = NULL; /* if no actual output file involved */ + /* Step 1: allocate and initialize JPEG decompression object */ - /* Initialize the system-dependent method pointers. */ - cinfo.methods = &dc_methods; /* links to method structs */ - cinfo.emethods = &e_methods; - /* Here we supply our own error handler; compare to use of standard error - * handler in the previous write_JPEG_file example. - */ - emethods = &e_methods; /* save struct addr for possible access */ - e_methods.error_exit = error_exit; /* supply error-exit routine */ - e_methods.trace_message = trace_message; /* supply trace-message routine */ - e_methods.trace_level = 0; /* default = no tracing */ - e_methods.num_warnings = 0; /* no warnings emitted yet */ - e_methods.first_warning_level = 0; /* display first corrupt-data warning */ - e_methods.more_warning_level = 3; /* but suppress additional ones */ - - /* prepare setjmp context for possible exit from error_exit */ - if (setjmp(setjmp_buffer)) { + /* 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)) { /* If we get here, the JPEG code has signaled an error. - * Memory allocation has already been cleaned up (see free_all call in - * error_exit), but we need to close the input file before returning. - * You might also need to close an output file, etc. + * We need to clean up the JPEG object, close the input file, and return. */ - fclose(cinfo.input_file); + jpeg_destroy_decompress(&cinfo); + fclose(infile); return 0; } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); - /* Here we use the standard memory manager provided with the JPEG code. - * In some cases you might want to replace the memory manager, or at - * least the system-dependent part of it, with your own code. - */ - jselmemmgr(&e_methods); /* select std memory allocation routines */ - /* If the decompressor requires full-image buffers (for two-pass color - * quantization or a noninterleaved JPEG file), it will create temporary - * files for anything that doesn't fit within the maximum-memory setting. - * You can change the default maximum-memory setting by changing - * e_methods.max_memory_to_use after jselmemmgr returns. - * On some systems you may also need to set up a signal handler to - * ensure that temporary files are deleted if the program is interrupted. - * (This is most important if you are on MS-DOS and use the jmemdos.c - * memory manager back end; it will try to grab extended memory for - * temp files, and that space will NOT be freed automatically.) - * See jcmain.c or jdmain.c for an example signal handler. + /* 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); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. */ - /* Here, set up the pointer to your own routine for post-header-reading - * parameter selection. You could also initialize the pointers to the - * output data handling routines here, if they are not dependent on the - * image type. - */ - dc_methods.d_ui_method_selection = d_ui_method_selection; + /* Step 4: set parameters for decompression */ - /* Set up default decompression parameters. */ - j_d_defaults(&cinfo, TRUE); - /* TRUE indicates that an input buffer should be allocated. - * In unusual cases you may want to allocate the input buffer yourself; - * see jddeflts.c for commentary. + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. */ - /* At this point you can modify the default parameters set by j_d_defaults - * as needed; for example, you can request color quantization or force - * grayscale output. See jdmain.c for examples of what you might change. + /* Step 5: Start decompressor */ + + jpeg_start_decompress(&cinfo); + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + 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); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + /* Assume put_scanline_someplace wants a pointer and sample count. */ + put_scanline_someplace(buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. */ - /* Set up to read a JFIF or baseline-JPEG file. */ - /* This is the only JPEG file format currently supported. */ - jselrjfif(&cinfo); + /* Step 8: Release JPEG decompression object */ - /* Here we go! */ - jpeg_decompress(&cinfo); + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); - /* That's it, son. Nothin' else to do, except close files. */ - /* Here we assume only the input file need be closed. */ - fclose(cinfo.input_file); - - /* You might want to test e_methods.num_warnings to see if bad data was - * detected. In this example, we just blindly forge ahead. + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) */ - return 1; /* indicate success */ + fclose(infile); - /* Note: if you want to decompress more than one image, we recommend you - * repeat this whole routine. You MUST repeat the j_d_defaults()/alter - * parameters/jpeg_decompress() sequence, as some data structures allocated - * in j_d_defaults are freed upon exit from jpeg_decompress. + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ + + /* And we're done! */ + return 1; } + + +/* + * SOME FINE POINTS: + * + * In the above code, we ignored the return value of jpeg_read_scanlines, + * which is the number of scanlines actually read. We could get away with + * this because we asked for only one line at a time and we weren't using + * a suspending data source. See libjpeg.doc for more info. + * + * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); + * we should have done it beforehand to ensure that the space would be + * counted against the JPEG max_memory setting. In some systems the above + * code would risk an out-of-memory error. However, in general we don't + * know the output image dimensions before jpeg_start_decompress(), unless we + * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. + * + * Scanlines are returned in the same order as they appear in the JPEG file, + * which is standardly top-to-bottom. If you must emit data bottom-to-top, + * you can use one of the virtual arrays provided by the JPEG memory manager + * to invert the data. See wrbmp.c for an example. + * + * As with compression, some operating modes may require temporary files. + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + */