/* * This software is copyrighted as noted below. It may be freely copied, * modified, and redistributed, provided that the copyright notice is * preserved on all copies. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * You may not include this software in a program or other software product * without supplying the source, or without informing the end-user that the * source is available for no extra charge. * * If you modify this software, you should include a notice giving the * name of the person performing the modification, the date of modification, * and the reason for such modification. */ /* * jpeg.c - interface with the JPEG format. * * Author: Raul Rivero * Mathematics Dept. * University of Oviedo * Date: Fri Mar 12 1993 * Copyright (c) 1993, Raul Rivero * */ /* * Raul Rivero - 09/26/94 * * New code has been added to support the new "The Independent JPEG * Group's Library", the 5.?. * * There is a problem to known the version of the IJL library, the * include headers have changed ( jinclude.h --> jpeglib.h ) so we * cannot get the version from the JPEG_LIB_VERSION define. * * You'll need define iJPEGNEW to get the new code, sorry :). * */ #include #include /* * Look here !!! * ============= * * This code is valid only if we have defined the iJPEG or iJPEGNEW * macro ( read the root Makefile for more information ). * */ #ifdef iJPEG #include static bitmap_hdr *jpeg_image; byte *jpeg_r, *jpeg_g, *jpeg_b; extern int LUGverbose; /* * Predefine what we'll need. */ void set_jpeg_header( #ifdef USE_PROTOTYPES compress_info_ptr #endif ); void set_jpeg_row( #ifdef USE_PROTOTYPES compress_info_ptr , JSAMPARRAY #endif ); void end_set_jpeg( #ifdef USE_PROTOTYPES compress_info_ptr #endif ); void c_ui_method_selection( #ifdef USE_PROTOTYPES compress_info_ptr #endif ); void get_jpeg_header( #ifdef USE_PROTOTYPES decompress_info_ptr #endif ); void get_jpeg_cmap( #ifdef USE_PROTOTYPES decompress_info_ptr , int , JSAMPARRAY #endif ); void get_jpeg_row( #ifdef USE_PROTOTYPES decompress_info_ptr , int , JSAMPIMAGE #endif ); void end_put_jpeg( #ifdef USE_PROTOTYPES decompress_info_ptr #endif ); void d_ui_method_selection( #ifdef USE_PROTOTYPES decompress_info_ptr #endif ); write_jpeg_file( name, bitmap ) char *name; bitmap_hdr *bitmap; { FILE *handle; if ( name ) handle = (FILE *) Fopen( name, "wb" ); else handle = stdout; /* Do it ! */ write_jpeg( handle, bitmap ); Fclose( handle ); } write_jpeg( handle, bitmap ) FILE *handle; bitmap_hdr *bitmap; { /* Write the JPEG image with a quality = 75 */ write_jpeg_opt( handle, bitmap, 75 ); } write_jpeg_opt( handle, bitmap, quality ) FILE *handle; bitmap_hdr *bitmap; int quality; { struct Compress_info_struct cinfo; struct Compress_methods_struct c_methods; struct External_methods_struct e_methods; if ( bitmap->magic != LUGUSED ) error( 19 ); VPRINTF( stderr, "Writing a JPEG image ( quality = %d )\n", quality ); /* Initialize the system-dependent method pointers. */ cinfo.methods = &c_methods; /* links to method structs */ cinfo.emethods = &e_methods; /* Select std error/trace message & memory allocation routines */ jselerror( &e_methods ); jselmemmgr( &e_methods ); /* Initialize pointer to raw data */ jpeg_image = bitmap; jpeg_r = jpeg_image->r; jpeg_g = jpeg_image->g; jpeg_b = jpeg_image->b; /* Define our own routines for input data handling */ c_methods.input_init = set_jpeg_header; c_methods.get_input_row = set_jpeg_row; c_methods.input_term = end_set_jpeg; c_methods.c_ui_method_selection = c_ui_method_selection; /* Set up JPEG parameters in the cinfo data structure. */ j_c_defaults( &cinfo, quality, FALSE ); #ifdef ENTROPY_OPT_SUPPORTED /* Best results */ cinfo.optimize_coding = TRUE; #endif /* No input file */ cinfo.input_file = NULL; /* Assign the output file */ cinfo.output_file = handle; /* Here we go! */ VPRINTF( stderr, "Encoding JPEG\n" ); jpeg_compress( &cinfo ); } void set_jpeg_header( cinfo ) compress_info_ptr cinfo; /* Initialize for input; return image size and component data. */ { cinfo->image_width = jpeg_image->xsize; cinfo->image_height = jpeg_image->ysize; 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 */ } void set_jpeg_row( cinfo, pixel_row ) compress_info_ptr cinfo; JSAMPARRAY pixel_row; /* Read next row of pixels into pixel_row[][] */ { 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) *jpeg_r++; /* red */ *ptr1++ = (JSAMPLE) *jpeg_g++; /* green */ *ptr2++ = (JSAMPLE) *jpeg_b++; /* blue */ } } void end_set_jpeg( cinfo ) compress_info_ptr cinfo; /* Finish up at the end of the input */ { /* Defined only for compatibility reasons */ VPRINTF( stderr, "JPEG process finished\n" ); } void c_ui_method_selection( cinfo ) 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); } read_jpeg_file( name, bitmap ) char *name; bitmap_hdr *bitmap; { FILE *handle; /* Open the file descriptor */ if ( name != NULL ) handle = Fopen( name, "rb" ); else handle = stdin; /* Read the bitmap */ read_jpeg( handle, bitmap ); rm_compress(); /* Close the file */ Fclose( handle ); } read_jpeg( handle, bitmap ) FILE *handle; bitmap_hdr *bitmap; { struct Decompress_info_struct cinfo; struct Decompress_methods_struct dc_methods; struct External_methods_struct e_methods; jpeg_image = bitmap; cinfo.input_file = handle; cinfo.output_file = NULL; /* if no actual output file involved */ /* Initialize the system-dependent method pointers. */ cinfo.methods = &dc_methods; cinfo.emethods = &e_methods; /* Select std error/trace message & memory allocation routines */ jselerror( &e_methods ); jselmemmgr( &e_methods ); dc_methods.d_ui_method_selection = d_ui_method_selection; /* Set up default decompression parameters. */ j_d_defaults( &cinfo, TRUE ); /* Set up to read a JFIF or baseline-JPEG file. */ jselrjfif( &cinfo ); /* Here we go! */ jpeg_decompress( &cinfo ); } void get_jpeg_header( cinfo ) decompress_info_ptr cinfo; /* This routine should do any setup required */ { int totalsize = cinfo->image_width * cinfo->image_height; VPRINTF( stderr, "Reading JPEG header\n" ); /* Fill our bitmap header */ jpeg_image->xsize = cinfo->image_width; jpeg_image->ysize = cinfo->image_height; jpeg_image->depth = 24; jpeg_image->colors = ( 1 << jpeg_image->depth ); jpeg_image->magic = LUGUSED; /* Alloc memory */ jpeg_r = jpeg_image->r = (byte *) Malloc( totalsize ); jpeg_g = jpeg_image->g = (byte *) Malloc( totalsize ); jpeg_b = jpeg_image->b = (byte *) Malloc( totalsize ); } void get_jpeg_cmap( cinfo, num_colors, colormap ) 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, "get_jpeg_camp called: there's a bug here somewhere!\n"); } void get_jpeg_row( cinfo, num_rows, pixel_data ) decompress_info_ptr cinfo; int num_rows; JSAMPIMAGE pixel_data; /* Write some rows of output data */ { register FILE * outfile = cinfo->output_file; register JSAMPROW ptr0, ptr1, ptr2; register long col; register int row; VPRINTF( stderr, "\rUncoding JPEG ( position %d )", jpeg_r - jpeg_image->r ); VFLUSH( stderr ); 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++ ) { *jpeg_r++ = GETJSAMPLE(*ptr0); ptr0++; /* red */ *jpeg_g++ = GETJSAMPLE(*ptr1); ptr1++; /* green */ *jpeg_b++ = GETJSAMPLE(*ptr2); ptr2++; /* blue */ } } } void end_put_jpeg( cinfo ) decompress_info_ptr cinfo; /* Finish up at the end of the input */ { /* Defined only for compatibility reasons */ VPRINTF( stderr, "\nJPEG process finished\n" ); } void d_ui_method_selection( cinfo ) decompress_info_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; /* select output routines */ cinfo->methods->output_init = get_jpeg_header; cinfo->methods->put_color_map = get_jpeg_cmap; cinfo->methods->put_pixel_rows = get_jpeg_row; cinfo->methods->output_term = end_put_jpeg; } #else /* iJPEG */ # ifdef iJPEGNEW #include #include extern LUGverbose; read_jpeg_file( name, bitmap ) char *name; bitmap_hdr *bitmap; { FILE *handle; /* Open the file descriptor */ if ( name != NULL ) handle = Fopen( name, "rb" ); else handle = stdin; /* Read the bitmap */ read_jpeg( handle, bitmap ); rm_compress(); /* Close the file */ Fclose( handle ); } read_jpeg( handle, bitmap ) FILE *handle; bitmap_hdr *bitmap; { int i, j; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; byte *rptr, *gptr, *bptr; JSAMPLE *rgb_aux[1], *aux_ptr; /* Use the default IJL's error handlers */ cinfo.err = jpeg_std_error( &jerr ); /* Create the decompression object */ jpeg_create_decompress( &cinfo ); /* Read the file's header ... */ jpeg_stdio_src( &cinfo, handle ); (void) jpeg_read_header( &cinfo, TRUE ); /* ... and fill our header */ bitmap->magic = LUGUSED; bitmap->xsize = cinfo.image_width; bitmap->ysize = cinfo.image_height; VPRINTF( stderr, "Reading a JPEG image\n" ); VPRINTF( stderr, "\t%dx%d pixels\n", bitmap->xsize, bitmap->ysize ); /* What kind of image ? */ switch ( cinfo.num_components ) { case 1: /* A grayscaled image */ bitmap->depth = 8; bitmap->colors = 1 << bitmap->depth; bitmap->cmap = create_bw_pallete(); rptr = bitmap->r = (byte *) Malloc( bitmap->xsize * bitmap->ysize ); VPRINTF( stderr, "\tgrayscaled colorspace\n"); break; case 3: case 4: /* A true color image */ bitmap->depth = 24; bitmap->colors = 1 << bitmap->depth; rptr = bitmap->r = (byte *) Malloc( bitmap->xsize * bitmap->ysize ); gptr = bitmap->g = (byte *) Malloc( bitmap->xsize * bitmap->ysize ); bptr = bitmap->b = (byte *) Malloc( bitmap->xsize * bitmap->ysize ); /* We wanna rgb values from the IJL routines */ cinfo.out_color_space = JCS_RGB; VPRINTF( stderr, "\ttrue color space\n" ); break; default: /* Hmmmmmmm ?! */ jpeg_destroy_decompress( &cinfo ); /* Unset the LUG mark */ bitmap->magic = LUGUSED - 1; fprintf( stderr, "I don't know how to handle %d components in a JPEG file\n", cinfo.num_components ); error( 99 ); return; /* not used now, but ... */ break; } /* Start decompressor */ jpeg_start_decompress( &cinfo ); VPRINTF( stderr, "\tdecompressor started\n" ); /* Get memory for our tmp array */ rgb_aux[0] = (JSAMPLE *) Malloc( sizeof(JSAMPLE) * cinfo.output_width * cinfo.output_components ); j = 0; while ( cinfo.output_scanline < cinfo.output_height ) { /* Get the next sacnline */ (void) jpeg_read_scanlines( &cinfo, rgb_aux, 1 ); if ( ++j % 10 == 0 ) { VPRINTF( stderr, "\r\tprocessing line %d", cinfo.output_scanline); VFLUSH( stderr ); j = 0; } /* Unpack it */ for ( i = 0, aux_ptr = rgb_aux[0]; i < bitmap->xsize; i++ ) { *rptr++ = *aux_ptr++; if ( cinfo.output_components == 3 ) { *gptr++ = *aux_ptr++; *bptr++ = *aux_ptr++; } } } VPRINTF( stderr, "\r\tprocessed %d lines \n\tdone.\n", cinfo.output_scanline); /* Release our memory */ Free( rgb_aux[0] ); /* Say bye to the decompressor :) */ (void) jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); } write_jpeg_file( name, bitmap ) char *name; bitmap_hdr *bitmap; { FILE *handle; if ( name ) handle = (FILE *) Fopen( name, "wb" ); else handle = stdout; /* Do it ! */ write_jpeg( handle, bitmap ); Fclose( handle ); } write_jpeg( handle, bitmap ) FILE *handle; bitmap_hdr *bitmap; { /* Write the JPEG image with a quality = 75 */ write_jpeg_opt( handle, bitmap, 75 ); } write_jpeg_opt( handle, bitmap, quality ) FILE *handle; bitmap_hdr *bitmap; int quality; { int i, j; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; byte *rptr, *gptr, *bptr; JSAMPLE *rgb_aux[1], *aux_ptr; if ( bitmap->magic != LUGUSED ) error( 19 ); /* We need a true color or gray mapped image. Really ? */ if ( bitmap->depth < 24 && !isagrayscaled(bitmap) ){ /* * Ok, we have a mapped image ==> not supported. So it'll be converted * to true clor and ... voila. */ bitmap_hdr out; to24( bitmap, &out ); write_jpeg_opt( handle, &out, quality ); return 1; } /* Use the default IJL's error handlers */ cinfo.err = jpeg_std_error( &jerr ); /* Create the compression object */ jpeg_create_compress( &cinfo ); /* The destination is ... */ jpeg_stdio_dest( &cinfo, handle ); /* Fill the IJL's image header */ cinfo.image_width = bitmap->xsize; cinfo.image_height = bitmap->ysize; cinfo.input_components = ( bitmap->depth < 24 ? 1 : 3 ); cinfo.in_color_space = ( bitmap->depth < 24 ? JCS_GRAYSCALE : JCS_RGB ); VPRINTF( stderr, "Writting a JPEG file\n" ); VPRINTF( stderr, "\t%dx%d pixels\n", bitmap->xsize, bitmap->ysize ); VPRINTF( stderr, "\t%s color space\n", ( bitmap->depth < 24 ? "JCS_GRAYSCALE" : "JCS_RGB" )); /* Fix these stored values and the quality */ jpeg_set_defaults( &cinfo ); jpeg_set_quality( &cinfo, quality, TRUE ); VPRINTF( stderr, "\tquality fixed to %d\n", quality ); /* Start the compressor */ jpeg_start_compress(&cinfo, TRUE); VPRINTF( stderr, "\tcompressor started\n" ); /* Get memory for our tmp array */ rgb_aux[0] = (JSAMPLE *) Malloc( sizeof(JSAMPLE) * cinfo.image_width * cinfo.input_components ); /* Initialize our pointers */ rptr = bitmap->r; if ( cinfo.input_components == 3 ) { gptr = bitmap->g; bptr = bitmap->b; } /* And ... the loop! :) */ while (cinfo.next_scanline < cinfo.image_height) { if ( ++j % 10 == 0 ) { VPRINTF( stderr, "\r\tprocessing line %d", cinfo.next_scanline); VFLUSH( stderr ); j = 0; } /* Pack the r-g-b data */ for ( i = 0, aux_ptr = rgb_aux[0]; i < bitmap->xsize; i++ ) { *aux_ptr++ = *rptr++; if ( cinfo.input_components == 3 ) { *aux_ptr++ = *gptr++; *aux_ptr++ = *bptr++; } } (void) jpeg_write_scanlines( &cinfo, rgb_aux, 1 ); } VPRINTF( stderr, "\r\tprocessed %d lines \n\tdone.\n", cinfo.image_height ); /* Free our memory */ Free( rgb_aux[0] ); /* And close the compressor */ jpeg_finish_compress( &cinfo ); jpeg_destroy_compress( &cinfo ); return 1; } # endif /* iJPEGNEW */ #endif /* iJPEG */