/*
 * class ColorImage
 *
 * $Date$
 * $Revision$
 *
 */

#ifndef COLOR_IMAGE_HH__
#define COLOR_IMAGE_HH__

#include "WImage/Image.hh"
#include "WImage/ColorBuffer.hh"

/**
 * @addtogroup WImage
 * @{ */

/**
 * An image wrapper for bitmap images of three color components.
 * Objects may import and export different bitmap formats,
 * such as PPM. The color models can be changed (RGB or YUV).
 */
class
ColorImage : public ColorBuffer
{
public:
  /** Constructor. Creates objects and sets actual start values.
   * @param colors
   * the number of colors, and therefore the array's length
   * @param cmodel
   * the color model
   * @param images
   * an array of {\em colors} images to copy the channel data from
   * @param ownership
   * if true, only references to the images will be copied, and they will
   * not be deleted at object destruction, else the images will be cloned
   * and destroyed in the end
   * @param isMine if true the incoming images will not be cloned, i.e. 
   * ownership is transferred to this color image */
  ColorImage (int colors = 3, clrmodel cmodel = cm_rgb,
              Image **images = NULL, bool isReference = false,
	      bool isMine = false);
  /** Constructor. Creates an image of a given size.
   * @param rows
   * the number of image rows to create
   * @param cols
   * the number of image cols to create
   * @param colors
   * the number of colors
   * @param cmodel
   * the color model
   */
  ColorImage (int rows, int cols, int colors = 3, clrmodel cmodel = cm_rgb);

  /** Destructor. Frees allocated objects. */
  virtual ~ColorImage (void);

  /** Returns a reference to one of the color channels.
   * {\em Don't change the dimensions of single channels unless you know
   * what you're doing!}
   * @param num the number of the color channel
   * @return the color channel as a reference to an Image object */
  inline Image &channel (int num) { return *m_images[num]; }

  /** Returns a reference to one of the color channels.
   * {\em Don't change the dimensions of single channels unless you know
   * what you're doing!}
   * @param num the number of the color channel
   * @return the color channel as a reference to an Image object */
  inline const Image &channel (int num) const { return *m_images[num]; }

#ifndef _WIN32_WCE
  /** Read the image. All steps independent of the file format will be
   * performed, like testing for file readability etc.
   * @exception invalid_argument
   * invalid file format
   * @exception ios_base::failure
   * a read error has occured [not supported by all libraries, so eventually
   * {\em invalid_argument} instead] */
  void read (char const *fname);
  /** Read an image. Reads an image from a file using the specified
   * file type. Currently PGM, RAW and PFI are supported.
   * @exception invalid_argument
   * the file type is either not supported or could not be determined
   * from the given file name
   * @param fname
   * the file name, if {\em NULL}, then {\em stdin}
   * @param ftype
   * the file type */
  void read (char const *fname, filetype ftype);

  /** Write the image. All steps independent of the file format will be
   * performed, like testing for file writeability etc.
   * @exception ios_base::failure
   * a read error has occured [not supported by all libraries, so eventually
   * {\em invalid_argument} instead]
   * @exception invalid_argument
   * the source image has a different number of colors than the target
   * format allows
   * @param fname
   * the target file name
   * @param beautify
   * beautify images that have not had more analysis than synthesis steps? */
  void write (char const *fname, bool beautify = false);
  /** Write an image (abstract). Writes an image to a file using the
   * specified file type.
   * @param ftype
   * the file type
   * @param fname
   * the file name, if {\em NULL}, then {\em stdout}
   * @param beautify
   * beautify images that have not had more analysis than synthesis steps? */
  void write (char const *fname, filetype ftype, bool beautify = false);
#endif

  /** Return a new greyscale image containing the three color channels'
   * averages
   * @return the new image */
  Image *averageImage (void);

  /** Do an intelligent kind of beautification considering previous
   * transform steps. The original data will be overwritten, so this
   * should only be used on clones or if the image is not going to be
   * transformed afterwise. One region inside the image could be the
   * low-pass subband and should thus be handled separately. If that is
   * desired, the {\em ysize} and {\em xsize} parameters should be set
   * to nonzero values.
   * @param ysize
   * the horizontal size of the region that should be handled separately
   * @param xsize
   * the vertical size of the region that should be handled separately
   * @param yoffs
   * the horizontal offset of the region that should be handled separately
   * @param xoffs
   * the vertical offset of the region that should be handled separately */
  virtual void beautify (int yoffs = 0, int xoffs = 0,
                         int ysize = 0, int xsize = 0);

  /** Produce a copy of this image.
   * @return the copy */
  ColorImage *clone (void) const;
  /** Copy all data from a source image.
   * @param img
   * the source image
   * @exception invalid_argument if the two images' number of color channels
   * do not match */
  virtual void copy (ColorImage &img);

  /** Return the current image quality factor.
   * @return the current image quality factor */
  inline int quality (void)  const{ return m_quality; }

  /** Sets a new image quality factor.
   * @return the new image quality factor */
  inline void quality (int quality)  { m_quality = quality; }

  /** Returns a subimage.
   * @param yoffs
   * the row where to start
   * @param xoffs
   * the col where to start
   * @param ysize
   * the vertical size
   * @param xsize
   * the horizontal size
   * @return
   * the new image */
  ColorImage *crop (int yoffs, int xoffs, int ysize, int xsize) const;
  /** Inserts a subimage.
   * @param yoffs
   * the row where to start
   * @param xoffs
   * the col where to start
   * @param img
   * the image to insert
   * @exception invalid_argument if the two images' number of color channels
   * do not match */
  virtual void paste (int yoffs, int xoffs, ColorImage &img);
  /** Shift an Image.
   * @param yoffs
   * the rows to shift
   * @param xoffs
   * the cols to shift */
  virtual void shift (int yoffs, int xoffs);
  /** Fills an image (or regions of it) with a given value
   * @param values an array of this->colors() entries containing the the new
   * values one per channel for the selected positions (coeff values)
   * @param fromY the first point's row
   * @param fromX the first point's col
   * @param toY the second point's row (-1 if lower image border)
   * @param toX the second point's col (-1 if right image border)
   */
  void fill (coeff *values, int fromY = 0, int fromX = 0,
	     int toY = -1, int toX = -1);
  /** Fills an image (or regions of it) with a given value
   * @param values an array of this->colors() entries containing the the new
   * values one per channel for the selected positions (int values)
   * @param fromY the first point's row
   * @param fromX the first point's col
   * @param toY the second point's row (-1 if lower image border)
   * @param toX the second point's col (-1 if right image border)
   */
  void fill (int *values, int fromY = 0, int fromX = 0,
	     int toY = -1, int toX = -1);

  /** Produce a scaled version of the image which just fits into
   * the given dimensions. If the aspect ratio does not fit into
   * the new dimensions the remaining areas can be filled with a
   * given color or alternatively the resulting image will be smaller
   * than the target dimensions keeping its aspect ratio.
   * @exception invalid_argument
   * the factor is negative or the function argument is invalid
   * @param rows the target number of rows
   * @param cols the target number of columns
   * @param fill if not NULL it must point to an array of as many
   * values as color channels, so that each of the image's channels
   * has its own fill greyscale value for the remaining space
   * (else the a smaller image size will be chosen if the aspect ratio
   * does not match)
   * @param function interpolation function (0: bilinear interpolation,
   * 1: average, 2: nearest neighbour).
   * @return a new rescaled image */
  virtual ColorImage *fitInto (int rows, int cols,
			       int *fill = NULL, int function = 0) const;

  /** Produce a scaled version of the image which just fits into
   * the given dimensions. If the aspect ratio does not fit into
   * the new dimensions the remaining areas can be filled with a
   * given color or alternatively the resulting image will be smaller
   * than the target dimensions keeping its aspect ratio.
   * @exception invalid_argument
   * the factor is negative or the function argument is invalid
   * @param rows the target number of rows
   * @param cols the target number of columns
   * @param mirrorExtend if true, the otherwise empty regions of the image
   * are extended by a mirroring function
   * (else the a smaller image size will be chosen if the aspect ratio
   * does not match)
   * @param function interpolation function (0: bilinear interpolation,
   * 1: average, 2: nearest neighbour).
   * @return a new rescaled image */
  virtual ColorImage *fitInto (int rows, int cols, bool mirrorExtend,
			       int function = 0) const;

  /** Produce a scaled version of the image which just fits into
   * the given dimensions. If the aspect ratio does not fit into
   * the new dimensions the remaining areas can be filled with a
   * given color or alternatively the resulting image will be smaller
   * than the target dimensions keeping its aspect ratio.
   * @exception invalid_argument
   * the factor is negative or the function argument is invalid
   * @param rows the target number of rows
   * @param cols the target number of columns
   * @param extend the type of extension function used if the aspect
   * ratio does not match
   * (else the a smaller image size will be chosen if the aspect ratio
   * does not match)
   * @param function interpolation function (0: bilinear interpolation,
   * 1: average, 2: nearest neighbour).
   * @return a new rescaled image */
  virtual ColorImage *fitInto (int rows, int cols, ExtendFunc extend,
			       int function = 0) const;

  /** Produce a scaled version of the image which just fits into
   * the given dimensions. If the aspect ratio does not fit into
   * the new dimensions the remaining areas can be filled with a
   * given color or alternatively the resulting image will be smaller
   * than the target dimensions keeping its aspect ratio.
   * @exception invalid_argument
   * the factor is negative or the function argument is invalid
   * @param rows the target number of rows
   * @param cols the target number of columns
   * @param fillFunc if not NULL a function for filling otherwise empty regions
   * (else the a smaller image size will be chosen if the aspect ratio
   * does not match)
   * @param function interpolation function (0: bilinear interpolation,
   * 1: average, 2: nearest neighbour).
   * @return a new rescaled image */
  virtual ColorImage *fitInto (int rows, int cols, ResizeFillFunc *fillFunc,
			       int function = 0) const;

  /** Produce a scaled version of the image. The aspect ratio will remain
   * the same.
   * @exception invalid_argument
   * the factor is negative or the function argument is invalid
   * @param factor
   * the scale factor (>= 0, 1 for no change)
   * @param function interpolation function (0: bilinear interpolation,
   * 1: average, 2: nearest neighbour).
   * @return a new rescaled image */
  virtual ColorImage *scale (double factor, int function = 0) const;

  /** Produce a scaled version of the image. The aspect ratio depends on the
   * two scale factors
   * @exception invalid_argument
   * the factor is negative or the function argument is invalid
   * @param yFactor
   * the vertical scale factor (>= 0, 1 for no change)
   * @param xFactor
   * the horizontal scale factor (>= 0, 1 for no change)
   * @param function interpolation function (0: bilinear interpolation,
   * 1: average, 2: nearest neighbour).
   * @return a new rescaled image */
  virtual ColorImage *scale (double yFactor, double xFactor, int function = 0) const;

private:
  /** The image quality (if stored in lossy format like JPG) */
  int m_quality;
protected:
  /** Allocate objects and set standard values.
   * @param images
   * an array of {\em colors} images to copy the channel data from
   * @param isReference
   * if true, only references to the images will be copied, and they will
   * not be deleted at object destruction
   * @param isMine if true, the ownership of the incoming images will be
   * transferred to this color image */
  void init (Image **images = NULL, bool isReference = false, bool isMine = false);
  /** Deletes allocated objects. */
  virtual void destroy (void);
}; /* class ColorImage */

/** @} */

#endif /* COLOR_IMAGE_HH__ */

