/* jpegread.c needs jpeglib.h and libjpeg.a */ /* jpegread given a filename.jpg, alpha, returns width, height, rgb pixels */ /* int width, height; int alpha=0 to 255, or -1 for just rgb */ /* unsigned char pixels[4*width*height]; or 3*width*height for alpha=-1 */ /* call: status = jpegread("your-filename", alpha, &width, &height, pixels);*/ /* status==0 for OK */ #include #include "jpeglib.h" #include static void put_scanline(unsigned char buffer[], int line, int width, int height, int alpha, unsigned char rgbpix[]); static int debug = 0; /* = 1; prints every pixel */ /* IMAGE DATA FORMATS: * 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. R,G,B,A,R,G,B,A,... for RGB Alpha 32 bits per pixel */ /* * 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. */ 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; METHODDEF(void) my_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ my_error_ptr myerr = (my_error_ptr) cinfo->err; /* 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); } /* end my_error_exit */ int jpegread(char filename[], int alpha, int * width, int * height, unsigned char rgbpix[]) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct my_error_mgr jerr; FILE * infile; /* source file */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ if ((infile = fopen(filename, "rb")) == NULL) { if(debug)printf("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)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ 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); /* 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. */ /* Step 4: set parameters for decompression */ /* Step 5: Start decompressor */ (void) 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; *width = cinfo.output_width;; *height = cinfo.output_height; /* 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) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ (void) jpeg_read_scanlines(&cinfo, buffer, 1); /* Assume put_scanline_someplace wants a pointer and sample count. */ if(debug)printf("cinfo.output_scanline=%d\n", cinfo.output_scanline); if(debug)printf("cinfo.output_height=%d\n", cinfo.output_height); if(debug)printf("row_stride=%d\n", row_stride); put_scanline(buffer[0], cinfo.output_scanline, cinfo.output_width, cinfo.output_height, alpha, rgbpix); } /* 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. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); /* 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...) */ fclose(infile); return 0; } /* 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. */ static void put_scanline(unsigned char buffer[], int line, int width, int height, int alpha, unsigned char rgbpix[]) { int i, j, k; if(alpha<0 || alpha>255) { k = (height-line)*3*width; for(i=0; i<3*width; i+=3) { rgbpix[k+i] = buffer[i]; rgbpix[k+i+1] = buffer[i+1]; rgbpix[k+i+2] = buffer[i+2]; } } else { k = (height-line)*4*width; j = 0; for(i=0; i<3*width; i+=3) { if(debug)printf("i=%d, j=%d, k=%d, rgb=%03u %03u %03u \n", i, j, k, buffer[i], buffer[i+1], buffer[i+2]); rgbpix[k+j+i] = buffer[i]; rgbpix[k+j+i+1] = buffer[i+1]; rgbpix[k+j+i+2] = buffer[i+2]; rgbpix[k+j+i+3] = alpha; j++; } } } /* end put_scanline */