/* This implements the interface to the JPEG library for decompressing */
/* JPEG files, and also PPM/GIF/TGA. */


/*
 * 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 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.
 *
 * 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 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 <jinclude.h>

/*
 * <setjmp.h> is used for the optional error recovery mechanism shown in
 * the second part of the example.
 */

#include <setjmp.h>
#include <stdlib.h>
#include <string.h>

/* CONFIG: definitions for communication with other modules */
#include "shared.h"

static unsigned char *image_data_pointer;


static void error_exit() {
	printf("Error in JPEG file.\n");
	exit(1);
}

static void trace_message() {
}

static void *setjmp_buffer;


/******************** 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.
 */

/* <deleted */

/* CONFIG: Inserted progress monitor code from jdmain.c */

METHODDEF void
progress_monitor (decompress_info_ptr cinfo, long loopcounter, long looplimit)
{
  if (cinfo->total_passes > 1) {
    fprintf(stderr, "\rPass %d/%d: %3d%% ",
	    cinfo->completed_passes+1, cinfo->total_passes,
	    (int) (loopcounter*100L/looplimit));
  } else {
    fprintf(stderr, "\r %3d%% ",
	    (int) (loopcounter*100L/looplimit));
  }
  fflush(stderr);
}


/*
 * To accept the image data from decompression, you must define four routines
 * output_init, put_color_map, put_pixel_rows, and output_term.
 *
 * 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 are 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.
   */
   
   	/* CONFIG: Handle picture information */
   	image_width = cinfo->image_width;
   	image_height = cinfo->image_height;
	image_data_pointer = image_data; 
}


/*
 * 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 */
{
	/* CONFIG: Received quantized palette colors */
	int i;
	for (i = 0; i < num_colors; i++) {
		image_palette[i * 3] = colormap[0][i];
		image_palette[i * 3 + 1] = colormap[1][i];
		image_palette[i * 3 + 2] = colormap[2][i];
	}
/*	printf("Decompressing.\n"); */
  /* 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.
 */

static void writepixelrows ( int num_rows, int w, 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.
   */
  
	switch (image_colors) {
	case 256 : {
  		/* Handle pixel data (quantized to single 256 color LUT) */
  		int row;
  		for (row = 0; row < num_rows; row++) {
 			JSAMPROW ptr;
			ptr = pixel_data[0][row];
 			memcpy(image_data_pointer, ptr, w);	
 			image_data_pointer += w;
  		}
  		break;
  	}
	case 65536 * 256 : {
		int row;
		for (row = 0; row < num_rows; row++) {
			int col;
			JSAMPROW ptr0, ptr1, ptr2;
			ptr0 = pixel_data[0][row];
			ptr1 = pixel_data[1][row];
			ptr2 = pixel_data[2][row];
			for (col = 0; col < w; col++) {
				*image_data_pointer++ = *ptr2;
				*image_data_pointer++ = *ptr1;
				*image_data_pointer++ = *ptr0;
				ptr0++;
				ptr1++;
				ptr2++;
			}
		}
		break;
	}
	case 32768 : {
		int row;
		for (row = 0; row < num_rows; row++) {
			int col;
			JSAMPROW ptr0, ptr1, ptr2;
			ptr0 = pixel_data[0][row];
			ptr1 = pixel_data[1][row];
			ptr2 = pixel_data[2][row];
			for (col = 0; col < w; col++) {
				*(unsigned short *)image_data_pointer =
					(((unsigned short)*ptr0 >> 3) << 10) +
					(((unsigned short)*ptr1 >> 3) << 5) +
					((unsigned short)*ptr2 >> 3);
				ptr0++; ptr1++; ptr2++;
				image_data_pointer += 2; 
			}
		}
		break;
	}
	case 65536 : {
		int row;
		for (row = 0; row < num_rows; row++) {
			int col;
			JSAMPROW ptr0, ptr1, ptr2;
			ptr0 = pixel_data[0][row];
			ptr1 = pixel_data[1][row];
			ptr2 = pixel_data[2][row];
			for (col = 0; col < w; col++) {
				*(unsigned short *)image_data_pointer =
					(((unsigned short)*ptr0 >> 3) << 11) +
					(((unsigned short)*ptr1 >> 2) << 5) +
					((unsigned short)*ptr2 >> 3);
				ptr0++; ptr1++; ptr2++;
				image_data_pointer += 2; 
			}
		}
		break;
	}
	} /* switch */
}



METHODDEF void
put_pixel_rows (decompress_info_ptr cinfo, int num_rows, JSAMPIMAGE pixel_data)
/* Write some rows of output data */
{
	writepixelrows(num_rows, cinfo->image_width, pixel_data);
}


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.
 */


/*
 * 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. 
 *
 * 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).
 */

METHODDEF void
d_ui_method_selection (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;

	/* CONFIG: */
	switch (image_bytesperpixel) {
	case 1:
		cinfo->quantize_colors = TRUE;
		cinfo->desired_number_of_colors = 256;
		if (cinfo->jpeg_color_space == CS_GRAYSCALE)
			cinfo->two_pass_quantize = FALSE;
		break;
	case 2:
	case 3:
		cinfo->quantize_colors = FALSE;
		break;
	}

  	/* CONFIG: Allocate image buffer here */
  	image_data = malloc(cinfo->image_width * cinfo->image_height
  		* image_bytesperpixel);
	printf("Image size: %dx%d\n", cinfo->image_width,
		cinfo->image_height);
}


/*
 * 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.
 */

GLOBAL int
read_jpeg( 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.
   */
  struct Decompress_info_struct cinfo;
  struct Decompress_methods_struct dc_methods;
  struct External_methods_struct e_methods;

  /* Select the input and output files.
   * 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) {
    fprintf(stderr, "can't open %s\n", filename);
    return 0;
  }

  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.
   */
  /* CONFIG: Commented out next line */
  /* 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)) {
    /* 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.
     */
    fclose(cinfo.input_file);
    return 0;
  }

  /* 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.
   */

  /* 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;

  /* 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.
   */

  /* 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.
   */

  /* Set up to read a JFIF or baseline-JPEG file. */
  /* This is the only JPEG file format currently supported. */


    jselrjfif(&cinfo);
  
	dc_methods.progress_monitor = progress_monitor;

  /* Here we go! */
  jpeg_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.
   */
  return 1;			/* indicate success */

  /* 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.
   */
}


GLOBAL int
read_non_jpeg( 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.
   */
  struct Compress_info_struct cinfo;
  struct Compress_methods_struct dc_methods;
  struct External_methods_struct e_methods;
  int c, components, translate, row;
  JSAMPARRAY pixel_row, cmap_row;
  JSAMPIMAGE pixel_data;

  /* Select the input and output files.
   * 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) {
    fprintf(stderr, "can't open %s\n", filename);
    return 0;
  }
  if ((c = getc(cinfo.input_file)) == EOF)
    error_exit("Empty input file");
  fseek(cinfo.input_file, 0, 0);

  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.
   */
  /* CONFIG: Commented out next line */
  /* 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)) {
    /* 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.
     */
    fclose(cinfo.input_file);
    return 0;
  }

  /* 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.
   */

  /* 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; */

 switch (c) {
  case 'G':
    jselrgif(&cinfo);
    break;
  case 'P':
    jselrppm(&cinfo);
    break;
#if 0
  case 'R':
    jselrrle(&cinfo);
    break;
#endif
  case 0x00:
    jselrtarga(&cinfo);
    break;
}

/*	dc_methods.progress_monitor = progress_monitor; */

  /* Code from seejpeg. */
  (cinfo.methods->input_init) (&cinfo);
  components = cinfo.input_components;
  if ((c == 'G' || c == 'P') && components == 3 && image_bytesperpixel == 1) {
    components = 1;
    translate = 1;
    translate_init();
  } else {
    translate = 0;
  }
  
  	/* Allocate image buffer here */
  	image_data = malloc(cinfo.image_width * cinfo.image_height
  		* image_bytesperpixel);
	printf("Image size: %dx%d\n", cinfo.image_width,
		cinfo.image_height);
   	image_width = cinfo.image_width;
   	image_height = cinfo.image_height;
	image_data_pointer = image_data; 

  if (components == 1 && !translate) {
/*    display_set_greyscale_palette(); */
  }

  pixel_row = (*cinfo.emethods->alloc_small_sarray)
    (cinfo.image_width, (long) cinfo.input_components);
  if (translate) {
    cmap_row = (*cinfo.emethods->alloc_small_sarray)
	(cinfo.image_width, (long) components);
    pixel_data = (JSAMPIMAGE)(*cinfo.emethods->alloc_small_sarray)
      (sizeof(JSAMPROW *), (long) components);
    for (c = 0; c < components; c++) {
      pixel_data[c][0] = cmap_row[c];
    }
  } else {
    cmap_row = NULL;
    pixel_data = (JSAMPIMAGE)(*cinfo.emethods->alloc_small_sarray)
      (sizeof(JSAMPROW *), (long) cinfo.input_components);
    for (c = 0; c < cinfo.input_components; c++) {
      pixel_data[c][0] = pixel_row[c];
    }
  }

  for (row = 0; row < cinfo.image_height; row++) {
    (*cinfo.methods->get_input_row) (&cinfo, pixel_row);
    if (translate) {
      translate_row(cinfo.image_width, pixel_row, cmap_row);
    }
/*    display_rows(1, pixel_data, cinfo.image_width, components); */
    writepixelrows(1, cinfo.image_width, pixel_data);
  }

  (*cinfo.methods->input_term) (&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.
   */
  return 1;			/* indicate success */

  /* 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.
   */
}


void loadfile( char *filename ) {
	FILE *f;
	int c;
	char *type;
	if ((f = fopen(filename, "rb")) == NULL) {
		printf("Cannot open %s.\n", filename);
		exit(-1);
	}
	if ((c = getc(f)) == EOF) {
	    printf("Input file %s is empty.", filename);
	    exit(-1);
	}
	fclose(f);

  switch (c) {
  case 'G':
    printf("File type: %s\n", "GIF");
    read_non_jpeg(filename);
    break;
  case 'P':
    printf("File type: %s\n", "PPM");
    read_non_jpeg(filename);
    break;
#if 0
  case 'R':
    jselrrle(&cinfo);
    break;
#endif
  case 0x00:
    printf("File type: %s\n", "TARGA");
    read_non_jpeg(filename);
    break;
  default:
    printf("File type: %s\n", "JPEG");
    read_jpeg(filename);
    break;
  }
}
