# ifndef (PS_IMAGES_H)
# define PS_IMAGES_H

/* General image manipulation functions
 */

// image data type names 
typedef enum { 
    psU8  = 1, 
    psU16 = 2, 
    psU32 = 3, 
    psF32 = 4, 
    psF64 = 5, 
} psIMAGE_DEPTH;

// An array of real vectors 
PS_DECLARE_ARRAY_TYPE(psFloatArray);
PS_CREATE_ARRAY_TYPE(psFloatArray);

// image depth types 
typedef unsigned char  psU8;
typedef unsigned short psU16;
typedef unsigned long  psU32;
typedef float          psF32;
typedef double         psF64;

// overlay operations 
typedef enum { 
    psOVERLAY_EQUALS   = '=', 
    psOVERLAY_ADD      = '+', 
    psOVERLAY_SUBTRACT = '-', 
    psOVERLAY_MULTIPLY = '*', 
    psOVERLAY_DIVIDE   = '/', 
} psOVERLAY_OP;

// binary operations (image / vector?) 
typedef enum { 
    psBINARY_ADD        = '+', 
    psBINARY_SUBTRACT   = '-', 
    psBINARY_MULTIPLY   = '*', 
    psBINARY_DIVIDE     = '/', 
    psBINARY_POWER      = '^', 
    psBINARY_MIN, 
    psBINARY_MAX, 
    psBINARY_LESSTHAN   = '<', 
    psBINARY_MORETHAN   = '>', 
    psBINARY_ISEQUAL    = '==', 
    psBINARY_NOTEQUAL   = '!=', 
    psBINARY_LESSOREQ   = '<=', 
    psBINARY_MOREOREQ   = '>=', 
    psBINARY_AND        = '&&', 
    psBINARY_OR         = '||', 
    psBINARY_BITAND     = '&', 
    psBINARY_BITOR      = '|', 
    psBINARY_XOR        = '~', 
    psBINARY_ATAN2      = 'atan2', 
} psBINARY_OP;

// unary image operations 
typedef enum { 
    psUNARY_IS     = '=', 
    psUNARY_ABS,
    psUNARY_INT,
    psUNARY_EXP,
    psUNARY_TEN,
    psUNARY_LOG,
    psUNARY_LN,
    psUNARY_SQRT,
    psUNARY_SIN,
    psUNARY_COS,
    psUNARY_TAN,
    psUNARY_DSIN,
    psUNARY_DCOS,
    psUNARY_DTAN,
    psUNARY_ASIN,
    psUNARY_ACOS,
    psUNARY_ATAN,
    psUNARY_DASIN,
    psUNARY_DACOS,
    psUNARY_DATAN,
    psUNARY_RND,
    psUNARY_NOT,
    psUNARY_NEGATE = '-',
    psUNARY_INCR,
    psUNARY_DECR,
    psUNARY_ISINF,
    psUNARY_ISNAN
} psUNARY_OP;

// basic image data structure 
typedef struct psImage {
    int nx, ny;				// size of image 
    int x0, y0;				// data region relative to parent 
    psIMAGE_DEPTH depth;		// type of image 
    psF32 **rows;		        // == rows_f32 
    psU8  **rows_u8;			// pointers to psU8 data 
    psU16 **rows_u16;			// pointers to psU16 data 
    psU32 **rows_u32;			// pointers to psU32 data 
    psF32 **rows_f32;			// pointers to psF32 data 
    psF64 **rows_f64;			// pointers to psF64 data 
    psImage *parent;			// parent, if a subimage 
    psImage *children;			// children of this region 
    int Nchildren;			// number of subimages 
    psDlist md;				// metadata associated with image
    psObjectTable objtable;		// objects associated with image
} psImage;

/*** Image structure manipulation ***/
// create an image of the specified size and type 
psImage *
psAllocImage (int nx,			// image width 
	      int ny,			// image height 
	      psIMAGE_DEPTH depth	// image depth 
    );

// create a subimage of the specified area 
psImage *
psSubsetImage (psImage *image,		// parent image 
	       int nx,			// subimage width (<= image.nx - x0)  
	       int ny,			// subimage width (<= image.ny - y0)  
	       int x0,			// subimage x-offset (0 <= x0 < nx)   
	       int y0			// subimage y-offset (0 <= y0 < ny)   
    );

// destroy the specified image (destroy children if they exist) 
void 
psFreeImage (psImage *image		// free this image
);

// destroy the children of the specified image 
int 
psFreeImageChildren (psImage *image	// free children of this image
);

// create a copy of the specified image 
psImage *
psCopyImage (psImage *output, 		// target structure for output image data
	     psImage *input		// copy this image 
);

/*** various image pixel extractions ***/
// extract pixels from rectlinear region to a vector
psFloatArray *
psSliceImage (psImage *input, 		// extract slice from this image
	      int x, 			// starting x coord of region to slice
	      int y, 			// starting y coord of region to slice
	      int nx, 			// width of region in x
	      int ny, 			// width of region in y
	      enum direction, 		// direction of vector along slice
	      enum statmode		// statistic applied to pixel group to find output value
);

// extract pixels along a line to a vector 
psFloatArray *
psCutImage (psImage *input, 		// extract cut from this image
	    float xs, 			// starting x coord of cut
	    float ys, 			// starting y coord of cut
	    float xe, 			// ending x coord of cut
	    float ye, 			// ending y coord of cut
	    float dw, 			// width of cut
	    enum statmode		// statistic applied to pixel group to find output value
);

// extract radial annulii data to a vector 
psFloatArray *
psRadialCutImage (psImage *input, 	// extract profile from this image
		  float x, 		// center x coord of annulii
		  float y, 		// center y coord of annulii
		  float radius, 	// outer radius of annulii
		  float dr,		// radial step size of annulii
		  enum statmode		// statistic applied to pixel group to find output value
);

// extract a 2-d contour from an image at the given threshold
psFloatArrayArray *
psContourImage (psImage *input, 	// create contour for this image
		float threshold,	// contour image at this threshold
		int binning		// bin image by this value for contour calculation
);

// extract a 2-d contour from an image at the given threshold
psSpanArray *
psContourImage (psImage *input, 	// create contour for this image
		float threshold		//  image at this threshold
);

/*** various image geometry manipulation ***/
// rebin image to new scale
psImage *
psRebinImage (psImage *input, 		// rebin this image
	      float scale, 		// rebinning scale: doutput = scale*dinput
	      enum statmode		// statistic used in performing interpolation / summing
);

// rotate image by given angle 
psImage *
psRotateImage (psImage *input, 		// rotate this image
	       float angle		// rotate by this amount (degrees)
);

// shift image by an arbitrary number of pixels in either direction
// edge pixels value and newly exposed pixels are set to 'exposed'
psImage *
psShiftImage (psImage *input, 		// shift this image
	      float dx, 		// shift by this amount in x
	      float dy, 		// shift by this amount in y
	      float exposed		// set exposed pixels to this value
);

// roll image by an integer number of pixels in either direction
// edge pixels wrap to the other side (no values are lost)
psImage *
psRollImage (psImage *input, 		// roll this image
	     int dx, 			// roll this amount in x
	     int dy			// roll this amount in y
);

// determine statistics for image (or subimage)
// should we have one function for all stats, or multiple functions?
// how to represent the output values?
void
psStatImage (psImage *input, enum statmode);

// construct a histogram from an image (or subimage)
psHistogram *
psHistogramImage (psHistogram,		// input histogram description & target
		  psImage *input,	// determine histogram of this image
);

// fit a 2-D polynomial surface to an image
psFloatArrayArray *
psFitPolynomialImage (psImage *input, 	// image to fit
		      int xorder	// order of polynomial in x-dir
		      int yorder	// order of polynomial in y-dir
);

/*** image input/output routines ***/
// read an image or subimage from a named file
psImage *
psReadImageSection (psImage *output, 	// place data in this structure for output 
		    int x, 		// starting x coord of region
		    int y, 		// starting y coord of region
		    int dx, 		// x size of region (-1 for full range)
		    int dy, 		// y size of region (-1 for full range)
		    int z, 		// plane of interest
		    char *extname, 	// MEF extension name ("PHU" for primary header)
		    char *filename	// file to read data from
);

// read an image or subimage from file descriptor
psImage *
psFReadImageSection (psImage *output,	// place data in this structure for output 
		     int x,		// starting x coord of region		   
		     int y,		// starting y coord of region		   
		     int dx,		// x size of region (-1 for full range)	   
		     int dy,		// y size of region (-1 for full range)	   
		     int z,		// plane of interest			   
		     char *extname,	// MEF extension name ("PHU" for primary header)			   
		     FILE *f		// file descriptor to read data from		   
);

// write an image section to named file (which may exist)
psImage *
psWriteImageSection (psImage *input,    // image to write out
		     int x, 		// starting x coord of region		   
		     int y, 		// starting y coord of region		   
		     int z, 		// plane of interest			   
		     char *extname, 	// MEF extension name ("PHU" for primary header)			   
		     char *filename	// file to write data to		   
);

// write an image section to named file (which may exist)
psImage *
psFWriteImageSection (psImage *input,	// image to write out
		      int x, 		// starting x coord of region		   
		      int y, 		// starting y coord of region		   
		      int z, 		// plane of interest			   
		      char *extname, 	// MEF extension name			   
		      FILE *f		// file descriptor to write data to		   
);

// read only header from image file
psMetadata *
psReadImageHeader (psMetadata *output, 	// read data to this structure
		   char *extname, 	// MEF extension name ("PHU" for primary header)
		   char *filename	// file to read from
); 

// read only header from image file descriptor
psMetadata *
psReadImageHeader (psMetadata *output, 	// read data to this structure
		   char *extname, 	// MEF extension name ("PHU" for primary header)
		   FILE *f		// file descriptor to read from
); 

/*** image FFT operations ***/
psImage *
psFFTImage (psImage *input, 		// image to FFT
	    enum direction		// FFT direction 
);

/*** basic pixel manipulations ***/
// clip image values outside of range to given values 
int
psClipImage (psImage *input, 		// clip this image
	     float min, 		// clip pixels with values < min
	     float vmin, 		// set min-clipped pixels to vmin
	     float max, 		// clip pixels with values > max
	     float vmax			// set max-clipped pixels to vmax
);

// clip NaN image pixels to given value 
int
psClipNaNImage (psImage *input, 	// clip this image
		float value		// set nan pixels to this value
);

/*** image arithmetic ***/
// perform a binary operation on two images 
psImage *
psImageBinaryOp (psImage *out,		// destination image (may be NULL) 
		 psImage *in1,		// first input image 
		 psImage *in2,		// second input image 
		 psBINARY_OP OP		// operator 
    );

// perform a unary operation on an image
psImage *
psImageUnaryOp (psImage *out,		// destination image (may be NULL) 
		psImage *in1,		// input image 
		psUNARY_OP OP		// operator 
    );

// overlay subregion of image with another image
int 
psOverlayImage (psImage *image,		// input image 
		psImage *overlay,	// image to overlay 
		int x0,			// x offset of overlay subimage 
		int y0,			// y offset of overlay subimage 
		psOVERLAY_OP op		// overlay operation 
    );

# endif
