//<copyright>
//
// Copyright (c) 1993
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
//
//</copyright>


//<file>
//
//
// Name :       jpeg.C
//
// Purpose :    implements loading of JPEG (JFIF; *.jpg) images
//
// Created :     1 Oct 93    Peter Pichler
// Modified :   20 Oct 94    Bernhard Marschall (jpeg-5 library)
//
//
// Description:
//
//</file>


#include <stdio.h>
#include <stdlib.h>
#include <stream.h>
#include <setjmp.h>
#include <fcntl.h>
#include <hyperg/utils/hgunistd.h>

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

#include <InterViews/raster.h>


//static struct djpeg_dest_struct dinfo;
static jmp_buf      jmpState;

/**************************************************/

static int myrows = 0; // my counter for this picture

static Raster* the_raster;
static boolean dither;

/**************************************************/

static void start_output (j_decompress_ptr cinfo)
{
  int width  = cinfo->image_width;
  int height = cinfo->image_height;

  the_raster = new Raster(width, height, dither);

  myrows=0;
}

/**************************************************/

static void put_pixel_rows (j_decompress_ptr cinfo, 
                            int num_rows, JSAMPARRAY pixel_data)
{
  static unsigned int totrows = 0;
  JSAMPROW ptr;
  int width = cinfo->image_width;
  unsigned char red, green, blue;

  if (cinfo->out_color_space == JCS_GRAYSCALE) {
    for (register int row = 0; row < num_rows; row++) {
      ptr = pixel_data[row];
      if (the_raster)
        for (register int col = width; col > 0; col--) {
          red = GETJSAMPLE(*ptr++);
          the_raster->pokeChr(cinfo->image_width - col,
                              cinfo->image_height-1 - myrows,
                              red, red, red
          );
        }
      totrows++;
      myrows++;
    }
  }

  else {
    for (register int row = 0; row < num_rows; row++) {
    ptr = pixel_data[row];
      if (the_raster)
        for (register int col = width; col > 0; col--) {
          red = GETJSAMPLE(*ptr++);
          green = GETJSAMPLE(*ptr++);
          blue = GETJSAMPLE(*ptr++);
          the_raster->pokeChr(cinfo->image_width - col, 
                              cinfo->image_height-1 - myrows,
                              red, green, blue
          );
        }

      totrows++;
      myrows++;
    }
  }
}

/***************************************************/

int JpegLoad(FILE* fp, 
             Raster*& raster, 
             RasterAction* progress,
             boolean doDither)
{
  /* returns '1' on success, '0' on failure */
  raster = the_raster = nil;
  dither = doDither;

  int rtval;
  JSAMPARRAY buffer;
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;

  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);


  /* Set up longjmp for error recovery out of ErrorExit */
  rtval = setjmp(jmpState);
  if (rtval) {
    if (the_raster) {
      delete the_raster;
    }
    jpeg_destroy_decompress(&cinfo);
    raster = nil;
    return 0;
  }
  
  jpeg_stdio_src(&cinfo, fp);

  jpeg_read_header(&cinfo, TRUE);

  jpeg_start_decompress(&cinfo);
  int row_stride = cinfo.output_width * cinfo.output_components;
  buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
                                        row_stride, 1);

  start_output(&cinfo);

  float p = 0.0;
  float incp = 1.0 / float(cinfo.image_height);
  int abort = 0;

  while (cinfo.output_scanline < cinfo.output_height) {
    jpeg_read_scanlines(&cinfo, buffer, 1);
    put_pixel_rows(&cinfo, 1, buffer);

    // call callback
    if (progress) abort = progress->progress(p += incp);
    if (abort) break;
  }

  if (abort)
    jpeg_abort_decompress(&cinfo);
  else
    jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  fclose(fp);

  raster = the_raster;
  return 1;
}
