/***************************************************************** * fljpeg.c: FBM Release 1.2 24-Mar-93 Michael Mauldin * * Copyright (C) 1993 by Michael Mauldin. Permission is granted * to use this file in whole or in part for any purpose, educational, * recreational or commercial, provided that this copyright notice * is retained unchanged. This software is available to all free of * charge by anonymous FTP and in the UUNET archives. * * This code is based on example.c from the JPEG library. * * fljpeg.c: * * CONTENTS * read_jpeg (image, rfile, mstr, mlen) * write_jpeg (image, wfile) * * EDITLOG * LastEditDate = Mon Jun 25 00:18:04 1990 - Michael Mauldin * LastFileName = /usr2/mlm/src/misc/fbm/fljpeg.c * * HISTORY * 31-Mar-93 Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon * Created. *****************************************************************/ # include # include # include "fbm.h" # define RED 0 # define GRN 1 # define BLU 2 static FBM *fbm_image; /* Global to allow allow access to methods */ static int row; #ifndef lint static char *fbmid = "$FBM fljpeg.c <1.2> 24-Mar-93 (C) 1993 by Michael Mauldin, source \ code available free from MLM@CS.CMU.EDU and from UUNET archives$"; #endif # ifdef DO_JPEG # include # include # include "jinclude.h" /*================ Compressor ================*/ void input_init (cinfo) compress_info_ptr cinfo; { /* The fields are initialized in write_jpeg */ } /* * 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. */ void get_input_row (cinfo, pixel_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 obm; register unsigned char *ibm; register int k; register long col; if (row >= fbm_image->hdr.rows) return; /* Copy a row from each plane into the appropriate pixel_row */ for (k=0; kinput_components; k++) { obm = pixel_row[k]; ibm = &fbm_image->bm[k * fbm_image->hdr.plnlen + row * fbm_image->hdr.rowlen]; for (col = 0; col < cinfo->image_width; col++) { *obm++ = (JSAMPLE) *ibm++; } } row++; } void input_term (cinfo) compress_info_ptr cinfo; /* Finish up at the end of the input */ { /* no work to do */ } /* * This routine must determine what output JPEG file format is to be written, */ 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); } /**************************************************************** * write_jpeg: Set up methods and call compressor ****************************************************************/ write_jpeg (image, wfile, quality) FBM *image; FILE *wfile; int quality; { struct Compress_info_struct cinfo; struct Compress_methods_struct c_methods; struct External_methods_struct e_methods; /* Global for get_input_row */ fbm_image = image; /* Initialize the system-dependent method pointers. */ cinfo.methods = &c_methods; /* links to method structs */ cinfo.emethods = &e_methods; jselerror(&e_methods); /* select std error/trace message routines */ jselmemmgr(&e_methods); /* select std memory allocation routines */ /*-------- Code that normally goes in input_init --------*/ cinfo.image_width = image->hdr.cols; /* width in pixels */ cinfo.image_height = image->hdr.rows; /* height in pixels */ cinfo.input_components = image->hdr.planes; /* or 1 for grayscale */ if (cinfo.input_components == 1) { cinfo.in_color_space = CS_GRAYSCALE; } else { cinfo.in_color_space = CS_RGB; } cinfo.data_precision = image->hdr.physbits; /* bits/pixel comp. value */ row = 0; /*---------------------------------------------------*/ /* Here, set up pointers to your own routines for input data handling * and post-init parameter selection. */ c_methods.input_init = input_init; /* now a nop */ c_methods.get_input_row = get_input_row; c_methods.input_term = input_term; c_methods.c_ui_method_selection = c_ui_method_selection; /* Set up default JPEG parameters in the cinfo data structure. */ j_c_defaults(&cinfo, quality, TRUE); cinfo.input_file = NULL; /* if no actual input file involved */ cinfo.output_file = wfile; /* Here we go! */ jpeg_compress(&cinfo); } /* ================ Decompressor ================*/ /* These static variables are needed by the error routines. */ static jmp_buf setjmp_buffer; /* for return to caller */ static external_methods_ptr emethods; /* 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. */ void trace_message (msgtext) 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. */ void error_exit (msgtext) 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 */ } /**************************************************************** * output_init; ****************************************************************/ void output_init (cinfo) decompress_info_ptr cinfo; { int rowlen; /* Set image size */ fbm_image->hdr.rows = cinfo->image_height; fbm_image->hdr.cols = cinfo->image_width; fbm_image->hdr.bits = cinfo->data_precision; fbm_image->hdr.physbits = 8; fbm_image->hdr.planes = (cinfo->out_color_space == CS_GRAYSCALE) ? 1 : 3; /* * Check for too many bits of precision. In the future, we * should just truncate to the 8 highest bits in this case. */ if (cinfo->data_precision > 8) { char mbuf[256]; sprintf (mbuf, "error:input has %d bits precision, can only handle 8\n", cinfo->data_precision); error_exit (mbuf); } /* Make sure rowlen is extended to an even number of bytes */ if ((rowlen = fbm_image->hdr.cols) & 1) rowlen++; fbm_image->hdr.rowlen = rowlen; fbm_image->hdr.plnlen = rowlen * fbm_image->hdr.rows; /* ALways unmapped output */ fbm_image->hdr.clrlen = 0; /* Miscellaneous annotations */ fbm_image->hdr.aspect = 1.0; fbm_image->hdr.title[0] = '\0'; strcpy (fbm_image->hdr.credits, "via JPEG"); alloc_fbm (fbm_image); row = 0; /* Global variable used in put_pixel_rows */ } /* * This routine is called if and only if you have set cinfo->quantize_colors * to TRUE. We don't need this for FBM. */ void put_color_map () { fprintf(stderr, "put_color_map called: there's a bug here somewhere!\n"); } /***************************************************************** * put_pixel_rows: Called with 1 or more rows in top to bottom order *****************************************************************/ void put_pixel_rows (cinfo, num_rows, pixel_data) decompress_info_ptr cinfo; int num_rows; JSAMPIMAGE pixel_data; { register FILE * outfile = cinfo->output_file; register JSAMPROW ibm; register unsigned char *obm; register int i, j, k; for (j = 0; j < num_rows && row < fbm_image->hdr.rows; j++, row++) { for (k=0; k < fbm_image->hdr.planes; k++) { ibm = pixel_data[k][j]; obm = &fbm_image->bm[k * fbm_image->hdr.plnlen + row * fbm_image->hdr.rowlen]; for (i = cinfo->image_width; i > 0; i--, ibm++) { *obm++ = GETJSAMPLE (*ibm); } } } } void output_term () { /* no work to do */ } /***************************************************************** * Now we have overall control and parameter selection routines. *****************************************************************/ 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 = output_init; cinfo->methods->put_color_map = put_color_map; cinfo->methods->put_pixel_rows = put_pixel_rows; cinfo->methods->output_term = output_term; } /***************************************************************** * OK, here is the main function that actually causes everything to happen. * We assume here that all decompression parameters can be default values. * The routine returns 1 if successful, 0 if not. *****************************************************************/ read_jpeg (image, rfile) FBM *image; FILE *rfile; { struct Decompress_info_struct cinfo; struct Decompress_methods_struct dc_methods; struct External_methods_struct e_methods; fbm_image = image; /* Set input file from caller and specify no output files */ cinfo.input_file = rfile; cinfo.output_file = NULL; /* if no actual output file involved */ /* 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)) { fclose(cinfo.input_file); return (0); } jselmemmgr(&e_methods); dc_methods.d_ui_method_selection = d_ui_method_selection; j_d_defaults(&cinfo, TRUE); jselrjfif(&cinfo); /* Here we go! */ jpeg_decompress(&cinfo); fclose(cinfo.input_file); return (1); } # else /**************************************************************** * stubs for reading and writing JPEG, since the library isn't loaded ****************************************************************/ write_jpeg (image, wfile, quality) FBM *image; FILE *wfile; int quality; { fprintf (stderr, "JPEG support was not compiled into this executable\n"); exit (1); } read_jpeg (image, rfile) FBM *image; FILE *rfile; { fprintf (stderr, "JPEG support was not compiled into this executable\n"); exit (1); } # endif