/* spslut_py.c VERSION 4.0 */
/* $Revision: 1.6 $
/* $Log: spslut_py.c,v $
 * Revision 1.6  2005/02/10 17:44:58  sole
 * *** empty log message ***
 *
 * Revision 1.5  2005/02/10 16:17:15  sole
 * Removed some unused variables
 **/
/* CHANGES:

	[05-09-2002] A. Gobbo
	- Included min and max values to 8 bit colormaps 
  
	[11-03-2002] A. Gobbo
	- Included modes BGR and BGRX 

	[12-12-2001] A. Gobbo
	- Dimentions inverted in the returned array
	- Corrected memory leak bug     
*/
#include <stdio.h>      

#include <Python.h>         
#include <Numeric/arrayobject.h>
#include <sps_lut.h>

static PyObject *SPSLUTError;

PyObject *new_pyimage(const char *mode, unsigned xsize, unsigned ysize, 
		      void *data)
{
  return PyString_FromStringAndSize ((const char *)data, 
				     strlen(mode) * xsize * ysize);
}
   
static int natbyteorder()
{
  union {
    struct {
      unsigned char b1;
      unsigned char b2;
      unsigned char b3;
      unsigned char b4;
    } c;
    unsigned long p;
  } val;

  val.p = 1;
  if (val.c.b4 == 1) {
    return SPS_MSB;
  } else {
    return SPS_LSB;
  }
}

static PyObject *spslut_transform(self, args)
     PyObject *self, *args;
     
{
  char *key, *value;
  void *data;
  int type, cols, rows, reduc, fastreduc, meth, autoscale, mapmin=0, mapmax=255;
  int palette_code;
  double gamma, min, max;
  XServer_Info Xservinfo;
  void *palette;
  int prows, pcols, pal_entries;
  int byteorder, pixelsize;
  unsigned long redmask, greenmask, bluemask;
  void *r/*, *res*/;
  char *mode;
  PyArrayObject *src;
  PyObject *in_src;
  PyObject *res,*aux;

  if (!PyArg_ParseTuple(args, "O(ii)(id)sii(dd)|(ii)", &in_src, &reduc, 
			&fastreduc, &meth, &gamma, &mode, &palette_code,
			&autoscale, &min, &max,&mapmin, &mapmax)) 
		return NULL;
  
  if (strcmp(mode, "RGB") == 0) {
    Xservinfo.red_mask = 0x0000ff;
    Xservinfo.green_mask = 0x00ff00;
    Xservinfo.blue_mask = 0xff0000;
    Xservinfo.pixel_size = 3;
    Xservinfo.byte_order = natbyteorder();
  } else if (strcmp(mode, "RGBX") == 0) {
    Xservinfo.red_mask = 0x0000ff;
    Xservinfo.green_mask = 0x00ff00;
    Xservinfo.blue_mask = 0xff0000;
    Xservinfo.pixel_size = 4;
    Xservinfo.byte_order = natbyteorder();
  } 
  
  //###CHANGED - ALEXANDRE 11/03/2002 - Qt uses different order than Tkinter
  else if (strcmp(mode, "BGR") == 0) {
    Xservinfo.red_mask = 0xff0000;
    Xservinfo.green_mask = 0x00ff00;
    Xservinfo.blue_mask = 0x0000ff;
    Xservinfo.pixel_size = 3;
    Xservinfo.byte_order = natbyteorder();
  } else if (strcmp(mode, "BGRX") == 0) {
    Xservinfo.red_mask = 0xff0000;
    Xservinfo.green_mask = 0x00ff00;
    Xservinfo.blue_mask = 0x0000ff;
    Xservinfo.pixel_size = 4;
    Xservinfo.byte_order = natbyteorder();
  } 

    else if (strcmp(mode, "L") == 0 || strcmp(mode, "P") == 0  ) {
    Xservinfo.pixel_size = 1;
    Xservinfo.byte_order = natbyteorder();
    //mapmin = 0;
    //mapmax = 255;
  } else {
    PyErr_SetString(SPSLUTError, "Mode must be RGB, RGBX, BGR, BGRX, L or P");
    return NULL;
  }

  if (!(src = (PyArrayObject*) PyArray_ContiguousFromObject(in_src, 
   			    PyArray_NOTYPE, 2, 2))) {
    PyErr_SetString(SPSLUTError, "Input Array could is not a 2x2 array");
    return NULL;
  }

  switch (src->descr->type_num) {
  case PyArray_UINT:
    type = SPS_ULONG; break;
  case PyArray_USHORT:
    type = SPS_USHORT; break;
  case PyArray_LONG: 
  case PyArray_INT: 
    type = SPS_LONG; break;
  case PyArray_SHORT: 
    type = SPS_SHORT; break;
  case PyArray_UBYTE: 
    type = SPS_UCHAR; break;
  case PyArray_SBYTE: 
    type = SPS_CHAR; break;
  case PyArray_FLOAT: 
    type = SPS_FLOAT; break;
  case PyArray_DOUBLE: 
    type = SPS_DOUBLE; break;
  default:
    PyErr_SetString(SPSLUTError, "Input Array type not supported");
    return NULL;
  }
  
  data = src->data;
  cols = src->dimensions[1];  /*FIX THIS cols and rows are turned around */
  rows = src->dimensions[0];  /*###CHANGED - ALEXANDRE 24/07/2001*/


  
  r = SPS_PaletteArray (data, type, cols, rows, reduc, fastreduc, meth, gamma, 
			autoscale, mapmin, mapmax, Xservinfo, palette_code,
			&min, &max, &pcols, &prows, &palette, &pal_entries);
  if (r == 0) {
    PyErr_SetString(SPSLUTError, "Error while trying to calculate the image");
    return NULL;
  }
   /*###CHANGED - ALEXANDRE 24/07/2001*/
  aux=new_pyimage(mode, (unsigned) pcols, (unsigned) prows, r);
  res = Py_BuildValue("(O(i,i)(d,d))",aux,pcols, prows, min, max);
  free(r);
  Py_DECREF(aux);

  /*###CHANGED - ALEXANDRE 28/06/2002*/  
  Py_DECREF(src);


  return res;
 
  /*
  res = Py_BuildValue("(O(i,i)(d,d))",  new_pyimage(mode, (unsigned) pcols, 
		(unsigned) prows, r), pcols, prows, min, max);
		(unsigned) prows, r), pcols, prows, min, max);
  free(r);  
  return res;
  */
}
static PyObject *spslut_transformfloat(self, args)
     PyObject *self, *args;
     
{
  char *key, *value;
  void *data;
  int type, cols, rows, reduc, fastreduc, meth, autoscale, mapmin=0, mapmax=255;
  int palette_code;
  double gamma, min, max;
  XServer_Info Xservinfo;
  void *palette;
  int prows, pcols, pal_entries;
  int byteorder, pixelsize;
  unsigned long redmask, greenmask, bluemask;
  void *r/*, *res*/;
  char *mode;
  PyArrayObject *src;
  PyObject *in_src;
  PyObject *res,*aux;

  if (!PyArg_ParseTuple(args, "O(ii)(id)sii(dd)|(ii)", &in_src, &reduc, 
			&fastreduc, &meth, &gamma, &mode, &palette_code,
			&autoscale, &min, &max,&mapmin, &mapmax)) 
		return NULL;
  
  if (strcmp(mode, "RGB") == 0) {
    Xservinfo.red_mask = 0x0000ff;
    Xservinfo.green_mask = 0x00ff00;
    Xservinfo.blue_mask = 0xff0000;
    Xservinfo.pixel_size = 3;
    Xservinfo.byte_order = natbyteorder();
  } else if (strcmp(mode, "RGBX") == 0) {
    Xservinfo.red_mask = 0x0000ff;
    Xservinfo.green_mask = 0x00ff00;
    Xservinfo.blue_mask = 0xff0000;
    Xservinfo.pixel_size = 4;
    Xservinfo.byte_order = natbyteorder();
  } 
  
  //###CHANGED - ALEXANDRE 11/03/2002 - Qt uses different order than Tkinter
  else if (strcmp(mode, "BGR") == 0) {
    Xservinfo.red_mask = 0xff0000;
    Xservinfo.green_mask = 0x00ff00;
    Xservinfo.blue_mask = 0x0000ff;
    Xservinfo.pixel_size = 3;
    Xservinfo.byte_order = natbyteorder();
  } else if (strcmp(mode, "BGRX") == 0) {
    Xservinfo.red_mask = 0xff0000;
    Xservinfo.green_mask = 0x00ff00;
    Xservinfo.blue_mask = 0x0000ff;
    Xservinfo.pixel_size = 4;
    Xservinfo.byte_order = natbyteorder();
  } 

    else if (strcmp(mode, "L") == 0 || strcmp(mode, "P") == 0  ) {
    Xservinfo.pixel_size = 1;
    Xservinfo.byte_order = natbyteorder();
    //mapmin = 0;
    //mapmax = 255;
  } else {
    PyErr_SetString(SPSLUTError, "Mode must be RGB, RGBX, BGR, BGRX, L or P");
    return NULL;
  }

  if (!(src = (PyArrayObject*) PyArray_ContiguousFromObject(in_src, 
   			    PyArray_DOUBLE, 0, 0))) {
    PyErr_SetString(SPSLUTError, "Input Array could is not a 2x2 array");
    return NULL;
  }

  switch (src->descr->type_num) {
  case PyArray_UINT:
    type = SPS_ULONG; break;
  case PyArray_USHORT:
    type = SPS_USHORT; break;
  case PyArray_LONG: 
  case PyArray_INT: 
    type = SPS_LONG; break;
  case PyArray_SHORT: 
    type = SPS_SHORT; break;
  case PyArray_UBYTE: 
    type = SPS_UCHAR; break;
  case PyArray_SBYTE: 
    type = SPS_CHAR; break;
  case PyArray_FLOAT: 
    type = SPS_FLOAT; break;
  case PyArray_DOUBLE: 
    type = SPS_DOUBLE; break;
  default:
    PyErr_SetString(SPSLUTError, "Input Array type not supported");
    return NULL;
  }
  
  data = src->data;
  cols = src->dimensions[1];  /*FIX THIS cols and rows are turned around */
  rows = src->dimensions[0];  /*###CHANGED - ALEXANDRE 24/07/2001*/


  
  r = SPS_PaletteArray (data, type, cols, rows, reduc, fastreduc, meth, gamma, 
			autoscale, mapmin, mapmax, Xservinfo, palette_code,
			&min, &max, &pcols, &prows, &palette, &pal_entries);
  if (r == 0) {
    PyErr_SetString(SPSLUTError, "Error while trying to calculate the image");
    return NULL;
  }
   /*###CHANGED - ALEXANDRE 24/07/2001*/
  aux=new_pyimage(mode, (unsigned) pcols, (unsigned) prows, r);
  res = Py_BuildValue("(O(i,i)(d,d))",aux,pcols, prows, min, max);
  free(r);
  Py_DECREF(aux);

  /*###CHANGED - ALEXANDRE 28/06/2002*/  
  Py_DECREF(src);


  return res;
 
  /*
  res = Py_BuildValue("(O(i,i)(d,d))",  new_pyimage(mode, (unsigned) pcols, 
		(unsigned) prows, r), pcols, prows, min, max);
		(unsigned) prows, r), pcols, prows, min, max);
  free(r);  
  return res;
  */
}
#ifndef DBL_MAX
#define DBL_MAX 1.7976931348623157e+308
#endif

#ifndef FLT_MAX
#define FLT_MAX 3.40282347e+38
#endif

#define FINDMINMAX(ty, maxval) \
{\
 register ty *c1=(ty *)data;\
 register int i;\
 register ty mmin, mmax, mminplus;\
 int size = cols*rows; \
 mmax = mmin = *c1;\
 mminplus = maxval;\
 if (dominmax && dominplus) { \
   for (i=size;i;i--,c1++) {\
     if (*c1 < mmin)\
       mmin = *c1;\
     if (*c1 > mmax)\
       mmax = *c1;\
     if ((*c1 < mminplus) && (*c1 > 0))\
       mminplus = *c1;\
   }\
 } else if (dominmax) {\
   for (i=size;i;i--,c1++) {\
     if (*c1 < mmin)\
       mmin = *c1;\
     if (*c1 > mmax)\
       mmax = *c1;\
   }\
 } else if (dominplus) {\
   if (mmin > 0) \
     mminplus = mmin;\
   else \
     for (i=size;i;i--,c1++) {\
       if ((*c1 < mminplus) && (*c1 > 0))\
         mminplus = *c1;\
   }\
 }\
 dmin = (double)mmin;\
 dmax = (double)mmax;\
 dminplus = (double)mminplus;\
}

static PyObject *spslut_transformarray(self, args)
     PyObject *self, *args;
     
{
  void *data;
  int type, cols, rows, reduc, fastreduc, meth, autoscale, mapmin=0, mapmax=255;
  int palette_code;
  double gamma, min, max;
  XServer_Info Xservinfo;
  void *palette;
  int prows, pcols, pal_entries;
  void *r/*, *res*/;
  char *mode;
  unsigned char  *as_r;
  int *as_pointer;
  int as_dim[3];
  PyArrayObject *src;
  PyObject *in_src;
  PyArrayObject *aux;
 int dominmax = 1;
 int dominplus = 1;
 int i;
 double dmin,dmax,dminplus, *test;
 unsigned char red, green, blue;
 
  if (!PyArg_ParseTuple(args, "Os(dd)|(ii)", &in_src, &mode, &min, &max,&mapmin, &mapmax)) 
		return NULL;
  if (!(src = (PyArrayObject*) PyArray_ContiguousFromObject(in_src, 
   			    PyArray_DOUBLE, 0, 0))) {
    PyErr_SetString(SPSLUTError, "Input Array could is not a 2x2 array");
    return NULL;
  }
  test = src->data;
  data = src->data;
  cols = src->dimensions[1];  /*FIX THIS cols and rows are turned around */
  rows = src->dimensions[0];  /*###CHANGED - ALEXANDRE 24/07/2001*/

  switch (src->descr->type_num) {
  case PyArray_UINT:
    type = SPS_ULONG; FINDMINMAX(unsigned long, ULONG_MAX);break;
  case PyArray_USHORT:
    type = SPS_USHORT; FINDMINMAX(unsigned short, USHRT_MAX);break;
  case PyArray_LONG: 
  case PyArray_INT: 
    type = SPS_LONG; FINDMINMAX(long, LONG_MAX);break;
  case PyArray_SHORT: 
    type = SPS_SHORT; FINDMINMAX(short, SHRT_MAX);break;
  case PyArray_UBYTE: 
    type = SPS_UCHAR; FINDMINMAX(unsigned char, UCHAR_MAX);break;
  case PyArray_SBYTE:
    type = SPS_CHAR; FINDMINMAX(char, SCHAR_MAX);break;
  case PyArray_FLOAT: 
    type = SPS_FLOAT; FINDMINMAX(float, DBL_MAX);break;
  case PyArray_DOUBLE: 
    type = SPS_DOUBLE; FINDMINMAX(double, DBL_MAX); break;
  default:
    PyErr_SetString(SPSLUTError, "Input Array type not supported");
    return NULL;
  }

/*  
int SPS_Size_VLUT (int t)
{
  switch (t) {
  case SPS_USHORT: return(sizeof(unsigned short));
  case SPS_ULONG:  return(sizeof(unsigned long));
  case SPS_SHORT:  return(sizeof(short));
  case SPS_LONG:   return(sizeof(long));
  case SPS_UCHAR:  return(sizeof(unsigned char));
  case SPS_CHAR:   return(sizeof(char));
  case SPS_STRING: return(sizeof(char));
  case SPS_DOUBLE: return(sizeof(double));
  case SPS_FLOAT:  return(sizeof(float));
  default:        return(0);
  }
}

   /*###CHANGED - ALEXANDRE 24/07/2001*/
  as_dim[0] = rows;
  as_dim[1] = cols;
/*  printf("dim[0] = %d dim[1] = %d \"%s\" \n",as_dim[0],as_dim[1],mode); */
  aux = (PyArrayObject*) PyArray_FromDims(2,as_dim, PyArray_INT);
  if (aux == NULL){
      Py_DECREF(src);
      return NULL;  
  }
  as_pointer = (int *) aux -> data;
  
  for (i=0; i< (rows * cols);i++){
    if (0){
        /*red*/
        *(as_pointer) = 0xFF;
        as_pointer++;
        /*green */
        *(as_pointer) = 0x00;
        as_pointer++;
        /*blue*/
        *(as_pointer) = 0x00;
        as_pointer++;
        /*dummy*/
        *(as_pointer) = 0xFF;
        as_pointer++;
    }else{
      /*  *(as_pointer) =(red << 0) | (green << 8) | (blue << 16);; */
        *(as_pointer) = 0xFF;
        /*256 * (*test - dmin) / (dmax-dmin);*/ 
        as_pointer++;
        test++;
    }
    
  } 
/*  as_r = (char *) r;  
  memcpy(as_pointer, as_r, as_dim[0] * as_dim[1]);
  free(r);*/
  
  
  Py_DECREF(src);
  PyArray_Return(aux);
}



/* The simple palette always returns 4 bytes per entry */
static PyObject *spslut_palette(self, args)
     PyObject *self, *args;
     
{
  int entries, palette_code;
  XServer_Info Xservinfo;
  void *r;
  char *mode;
  PyObject *res;

  if (!PyArg_ParseTuple(args, "ii", &entries, &palette_code)) 
    return NULL;
  
  mode = "RGBX";
  Xservinfo.red_mask = 0x0000ff;
  Xservinfo.green_mask = 0x00ff00;
  Xservinfo.blue_mask = 0xff0000;
  Xservinfo.pixel_size = 4;
  Xservinfo.byte_order = natbyteorder();

  r = SPS_SimplePalette ( 0, entries - 1, Xservinfo, palette_code); 
  
  if (r == 0) {
    PyErr_SetString(SPSLUTError, "Error calculating the palette");
    return NULL;
  }
  
  return new_pyimage(mode, 1, entries, r);
}


                                                                               
static PyMethodDef SPSLUTMethods[] = {
  { "transform", spslut_transform, METH_VARARGS},
  { "palette", spslut_palette, METH_VARARGS},
  { "transformFloat", spslut_transformfloat, METH_VARARGS},
  { "transformArray", spslut_transformarray, METH_VARARGS},
  { NULL, NULL}
};
  
void initspslut()
{
  PyObject *d, *m;
  /* Create the module and add the functions */
  m = Py_InitModule ("spslut", SPSLUTMethods);
  
  /* Add some symbolic constants to the module */
  d = PyModule_GetDict(m);

  PyDict_SetItemString(d, "LINEAR", PyInt_FromLong(SPS_LINEAR));
  PyDict_SetItemString(d, "LOG", PyInt_FromLong(SPS_LOG));
  PyDict_SetItemString(d, "GAMMA", PyInt_FromLong(SPS_GAMMA));

  PyDict_SetItemString(d, "GREYSCALE", PyInt_FromLong(SPS_GREYSCALE));
  PyDict_SetItemString(d, "TEMP", PyInt_FromLong(SPS_TEMP));
  PyDict_SetItemString(d, "RED", PyInt_FromLong(SPS_RED));
  PyDict_SetItemString(d, "GREEN", PyInt_FromLong(SPS_GREEN));
  PyDict_SetItemString(d, "BLUE", PyInt_FromLong(SPS_BLUE));
  PyDict_SetItemString(d, "REVERSEGREY", PyInt_FromLong(SPS_REVERSEGREY));
  PyDict_SetItemString(d, "MANY", PyInt_FromLong(SPS_MANY));

  SPSLUTError = PyErr_NewException("spslut.error", NULL, NULL);
  PyDict_SetItemString(d, "error", SPSLUTError);
  import_array();
}













