#include <config.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <errno.h>

#include "GFile_JPEG.h"

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

/* GFile (ie. GImage) decendent for reading JPEG files.
 *
 * Written by:  Chris Studholme
 * Last Update: 28-May-2000
 * Copyright:   GPL (http://www.fsf.org/copyleft/gpl.html)
 */


/* ================ GFile_JPEG methods  ================ */

GFile_JPEG::GFile_JPEG(const char* filename, bool fast) {

  red=green=blue=NULL;
  w=h=0;

  // allocate and initialize a JPEG compression object
  jpeg_decompress_struct cinfo;
  jpeg_error_mgr jerr;
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);
 
  // specify the source for the compressed data
  FILE* infile;
  if ((infile = fopen(filename, "rb")) == NULL) {
    fprintf(stderr, "can't open %s\n", filename);
    return;
  }
  jpeg_stdio_src(&cinfo, infile);

  // call jpeg_read_header() to obtain image info
  jpeg_read_header(&cinfo, TRUE);

  // set parameters for decompression
  cinfo.dct_method = JDCT_FLOAT;

  // jpeg_start_decompress(...);
  jpeg_start_decompress(&cinfo);
  w=cinfo.output_width;
  h=cinfo.output_height;
  if (cinfo.output_components!=3) {
    fprintf(stderr,"GFile_JPEG: only full color JPEG images are supported\n");
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    return;
  }
  
  int row_stride = cinfo.output_width * cinfo.output_components;
  /* Make a one-row-high sample array that will go away when done with image */
  JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)
    ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

  unsigned char* r = new unsigned char[w*h];
  unsigned char* g = new unsigned char[w*h];
  unsigned char* b = new unsigned char[w*h];
  
  // while (scan lines remain to be read)
  for (int y=0; y<h; ++y) {
    // jpeg_read_scanlines(...);
    jpeg_read_scanlines(&cinfo,buffer,1);
    for (int x=0; x<w; ++x) {
      r[y*w+x] = buffer[0][3*x+0];
      g[y*w+x] = buffer[0][3*x+1];
      b[y*w+x] = buffer[0][3*x+2];
    }
  }

  memset(histogram,0,sizeof(histogram));
  addToHistogram(histogram,r,w*h);
  addToHistogram(histogram,g,w*h);
  addToHistogram(histogram,b,w*h);

  // jpeg_finish_decompress(...);
  jpeg_finish_decompress(&cinfo);

  // release the JPEG decompression object
  jpeg_destroy_decompress(&cinfo);

  fclose(infile);

  // create linear mapping
  fprintf(stderr,"Initializing linear matrix... ");
  red = new GImageComponent0(r,w,h,fast?-1:0);
  delete[] r;
  
  fprintf(stderr,"red... ");
  green = new GImageComponent0(g,w,h,fast?-1:0);
  delete[] g;

  fprintf(stderr,"green... ");
  blue = new GImageComponent0(b,w,h,fast?-1:0);
  delete[] b;

  fprintf(stderr,"blue, done.\n");
  if (!fast)
    fprintf(stderr,"Total Error is %g\n",red->getTotalError()+
	    green->getTotalError()+blue->getTotalError());
}

GFile_JPEG::~GFile_JPEG() {
  if (red)
    delete red;
  if (green)
    delete green;
  if (blue)
    delete blue;
}

bool GFile_JPEG::supportsFile(FILE* file) {
  if (fseek(file,0,SEEK_SET)!=0) {
    fprintf(stderr,"GFile_JPEG::supportsFile() fseek() failed %d\n",errno);
    return false;
  }
  unsigned char header[2];
  if (fread(header,sizeof(header),1,file)!=1) {
    fprintf(stderr,"GFile_JPEG::supportsFile() fread() failed %d\n",errno);
    return false;
  }
  return ((header[0]==0x0FF)&&(header[1]==0x0D8));
}

 
