/*
 * $Id: readjpeg.cxx,v 4.1 2004/05/25 06:40:20 hut66au Exp $
 *
 * Imview, the portable image analysis application
 * http://www.cmis.csiro.au/Hugues.Talbot/imview
 * ----------------------------------------------------------
 *
 *  Imview is an attempt to provide an image display application
 *  suitable for professional image analysis. It was started in
 *  1997 and is mostly the result of the efforts of Hugues Talbot,
 *  Image Analysis Project, CSIRO Mathematical and Information
 *  Sciences, with help from others (see the CREDITS files for
 *  more information)
 *
 *  Imview is Copyrighted (C) 1997-2001 by Hugues Talbot and was
 *  supported in parts by the Australian Commonwealth Science and 
 *  Industry Research Organisation. Please see the COPYRIGHT file 
 *  for full details. Imview also includes the contributions of 
 *  many others. Please see the CREDITS file for full details.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 * */


/*------------------------------------------------------------------------
 *
 * Read the JPEG format
 * Thanks to the excellent jpeg library, this is the
 * easiest formats of all.
 *
 * Hugues Talbot	22 Jan 1998
 * Modification : Hugues Talbot	29 Apr 1998
 *   Well: except for the error handling code...
 *      
 *-----------------------------------------------------------------------*/

#include "imview.hxx"

#ifdef HAVE_JPEG   // if the JPEG library is available

#include <stdio.h>
#include <setjmp.h>
#include "imSystem.hxx"
#include "../imageIO.hxx"
#include "readjpeg.hxx"

// Read using jpeg library:

extern "C" {
#include "jpeglib.h"
}

extern imageIO *IOBlackBox;

static uchar *loadJpegImage(FILE *infile, int *w, int *h, int *d);


int readJpegImage(const char *name) /* file name */
{
    FILE *fp;
    uchar *outbuf; 
    int w, h, d;

    fp = im_fopen(name, "rb");
    if (!fp) {
	errprintf("readJpegImage: can't open file %s\n", name);
	return 0;
    }


    outbuf = loadJpegImage(fp, &w, &h, &d);

    if (outbuf != 0) {
	IOBlackBox->setImData(outbuf);
	IOBlackBox->setCurrImgWidth(w);
	IOBlackBox->setCurrImgHeight(h);
	IOBlackBox->setCurrImgThickness(1);
	IOBlackBox->setXOffset(0);
	IOBlackBox->setYOffset(0);
	IOBlackBox->setZOffset(0);
	IOBlackBox->setCurrImgNbComps(1); // only a single image in a JPEG file
	IOBlackBox->setCurrImgNbSamples(d);
	IOBlackBox->setCurrImgSpp(d); // needed here because no currBuffp
	IOBlackBox->setCurrPixType(IM_UINT1);
	IOBlackBox->setCurrImgType((d == 3) ? IM_RGB : IM_SPECTRUM);
	IOBlackBox->setImgDesc("JPEG");
    }
    
    fclose(fp);
    
    return (outbuf == 0);
}

// returns the number of frames present in
// a JPEG file
int jpegnbsubfiles(const char *)
{
    return 1; // not too strenuous an effort here...
}

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_output_message (j_common_ptr cinfo)
{
  char buffer[JMSG_LENGTH_MAX];

  /* Create the message */
  (*cinfo->err->format_message) (cinfo, buffer);

  /* Send it to stderr, adding a newline */
  errprintf("%s\n", buffer);
}


/*
 * Here's the routine that will replace the standard error_exit method:
 */

METHODDEF(void)
my_error_return (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. */
  my_output_message(cinfo);

  /* Return control to the setjmp point */
  longjmp(myerr->setjmp_buffer, 1);
}


static uchar *loadJpegImage(FILE *infile, /* file name */
			     int *w,	   /* x dimension */
			     int *h,	   /* y dimension */
			     int *d         /* depth of the image */
    )	
{
/** read a JPEG image file

RETURN VALUE:	unsigned char *

DESCRIPTION:
This function read a JPEG image

HISTORY:
quickly adapted from demo code in FL library
Hugues Talbot	28 Oct 1997

TESTS:

REFERENCES:

KEYWORDS:

**/

  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  unsigned char *ibuffer, *rp;
  
  /* 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_return;
  /* 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);
    return 0;
  }

  
  jpeg_create_decompress(&cinfo);
  jpeg_stdio_src(&cinfo, infile);
  jpeg_read_header(&cinfo, TRUE);
  jpeg_start_decompress(&cinfo);
  *w = cinfo.output_width;
  *h = cinfo.output_height;
  *d = cinfo.output_components;
  ibuffer = new unsigned char[(*w)*(*h)*(*d)];
  rp = ibuffer;
  while (rp < ibuffer + (*w)*(*h)*(*d)) {
    jpeg_read_scanlines(&cinfo, &rp, 1);
    rp += (*w)*(*d);
  }
  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  return ibuffer;
}


#else // HAVE_JPEG

// stubs
int readJpegImage(const char *name) {
    errprintf("This version of imview cannot read JPEG images\n");
    return 1;
}
    
int jpegnbsubfiles(const char *name) {
    return 0;
}

#endif
