// Emacs: -*- C++ -*-

//
//	Copyright 1994, Center for Computer Vision and Visualization,
//	University of Florida.  All rights reserved.
//

static char copyright[] = "Copyright 1993, Center for Computer Vision and Visualization,\nUniversity of Florida.  All rights reserved.\n";

static char IntDI_rcsid[] = "$Id: RGBDI.c,v 1.3.1.2 1995/01/13 19:37:42 thoth Exp thoth $";

//
// $Log: RGBDI.c,v $
// Revision 1.3.1.2  1995/01/13  19:37:42  thoth
// CoreImage has been re-merged with Image.  All special stuff should be
// friends of FBI now.
//
// Revision 1.3.1.1  1994/12/28  16:45:50  thoth
// Image I/O is now ROF.
// removed obsolete instantiation cruft.
//
// Revision 1.3  1994/08/22  15:20:29  thoth
// DOS-inspired name rework.
//
// Revision 1.2  1994/07/25  17:26:39  thoth
// Name sanitization
//
// Revision 1.1  1994/03/02  13:59:21  jnw
// Initial revision
//
//

#include	"Closure.h"
#include	"PSIter.h"

#include	"RGBDI.h"
#include	"VectorI.h"
#include	"ConstI.h"
#include	"ClosureI.h"
#include	"ErrorI.h"
#include	"ImageIter.h"

#include	<math.h>
#include	<fstream.h>
#include	<values.h>

//
//
//

#include "restrict.h"

IA_BaseImage<IA_Point<int>,IA_RGB> *restrict_toD(const IA_BaseImage<IA_Point<int>,IA_RGB> *im, const IA_Set<IA_Point<int> > &ips) {
    return restrictD_toD(im, ips);
}

IA_BaseImage<IA_Point<int>,IA_RGB> *restrict_toD(const IA_BaseImage<IA_Point<double>,IA_RGB> *im, const IA_Set<IA_Point<int> > &ips) {
    return restrictC_toD(im, ips);
}

//
//

istream &wsc(istream &);	// from UcharDI.c

inline int int_rgb_max(int i, IA_RGB rgb){
    int j = (rgb.red()>rgb.green())
	? (rgb.red()>rgb.blue()?rgb.red():rgb.blue())
	: (rgb.green()>rgb.blue()?rgb.green():rgb.blue());
    return i>j?i:j;
}
    

inline int ppm_max(IA_Image<IA_Point<int>,IA_RGB> im)
{
    IA_IVIter<IA_Point<int>,IA_RGB>	iter(im);
    IA_RGB rgb;
    int i=0;
    
    while(iter(rgb)){
	i = int_rgb_max(i,rgb);
    }
    return i;
}

IA_Image<IA_Point<int>,IA_RGB> read_PPM(istream &i, int*maxval_ret)
{
    int	width, height,maxval;
    int	code;
    if (i.get()=='P' && ((code=i.get())=='6' || code == '3')
	&& i>>wsc>>width>>wsc>>height>>wsc>>maxval) {
	if (maxval_ret)
	    *maxval_ret = maxval;
	{
	    int	ch = i.get();
	    if (ch!='\n')
		i.putback(ch);
	}
	const unsigned	size=width*height;
	IA_RGB	*data = new IA_RGB[size];
	if (code=='6') {
	    // p6 format
	    u_char	*tmp = new u_char[3*size];
	    if (!i.read(tmp, 3*size)) {
		delete[] data;
		ia_throw(Image_PNMIO_Exception(__FILE__, __LINE__));
		return IA_Image<IA_Point<int>,IA_RGB>();
	    }
	    for (unsigned i=0; i<size; i++)
		data[i] = IA_RGB(&(tmp[i*3]));
	    delete[] tmp;
	} else {
	    // P3 format
	    u_char tmp[3];
	    for (unsigned i=0; i<size; i++) {
		for (unsigned j=0; j < 3; j++) {
		    if (!cin >> tmp[j]) {
			delete[] data;
			ia_throw(Image_PNMIO_Exception(__FILE__, __LINE__));
			return IA_Image<IA_Point<int>,IA_RGB>();
		    }
		}
		data[i] = IA_RGB(tmp);
	    }
	}
	return IA_Image<IA_Point<int>,IA_RGB>
	    (IA_boxy_pset(IA_Point<int>(0,0), IA_Point<int>(height-1,width-1)),
	     data, size, 1);
    } else {
	ia_throw(Image_PNMIO_Exception(__FILE__, __LINE__));
	return IA_Image<IA_Point<int>,IA_RGB>();
    }
}

IA_Image<IA_Point<int>,IA_RGB> read_PPM(const char *fname, int *maxval)
{
    ifstream	in(fname);
    return read_PPM(in, maxval);
}

ostream &write_PPM(const IA_Image<IA_Point<int>,IA_RGB> &img, ostream &o, unsigned maxval)
{
    IA_Set<IA_Point<int> > boxydomain
	= IA_boxy_pset(img.domain().inf(),img.domain().sup());
    IA_Point<int>	width(img.domain().sup()-img.domain().inf()+1);

    // We only support P6 writing at this time.
    o<<"P6\n";

    o<<width[1] << " " << width[0] << " " << maxval << "\n";
    IA_PSIter<IA_Point<int> >	iter(boxydomain);
    IA_Point<int>	ip;

    while (iter(ip)) {
	IA_RGB pixel;

	pixel = img.domain().contains(ip)?img(ip):IA_RGB(0);
	o.put(pixel.red());
	o.put(pixel.green());
	o.put(pixel.blue());
    }
    return o;
}

ostream &write_PPM(const IA_Image<IA_Point<int>,IA_RGB> &img, ostream &o)
{
    int	max = ppm_max(img);
    return write_PPM(img, o, max>0 ? max : 1);
}

void write_PPM(const IA_Image<IA_Point<int>,IA_RGB> &img,
	       const char *fname, unsigned maxval)
{
    ofstream	out(fname);
    write_PPM(img, out, maxval);
}

void write_PPM(const IA_Image<IA_Point<int>,IA_RGB> &img,
	       const char *fname)
{
    ofstream	out(fname);
    int	max = ppm_max(img);
    write_PPM(img,out, max>0 ? max : 1);
}

//
// below are included the implementations of every image-image
// and image-scalar operation we could think of for RGB images.
//

inline int to_int(IA_RGB color){
    return color.to_int();
}

inline float to_float(IA_RGB color){
    return color.to_float();
}

inline u_char red(IA_RGB color){
    return color.red();
}

inline u_char green(IA_RGB color){
    return color.green();
}

inline u_char blue(IA_RGB color){
    return color.blue();
}

#include "RGBIOps.c"

//
//
//
