// File stream for opening and writing an image.
// This is basically similar to ofstream with additional depth for
// image specific information.  I have chosen to implement this on
// top ofthe UNIX style low level I/O calls rather than fstreams
// because I needto handle the buffering here and because of
// efficiency.
// example usage:
//      IMAGE_FORMAT format(type,pixel_bits,pixel_width,
					pixel_height,palette);
//      IMAGE_OUTPUT outfile;
//      if (!outfile.capable(&format)) { no can do; }
//      if (!outfile.open("filename",&format)) { error out; }
//      may need to do this in pieces:
//      outfile.write(buffer,total_image_lines);
//      tests write for failure:
//      if (!outfile) { error out; } 
//      also closed when out of scope 
//      if (!outfile.close()) { error out; } 

class IMAGE_OUTPUT
    {
    friend class IMAGE_OUTPUT_REGISTRY;
    public:
        IMAGE_OUTPUT() : _format(0) { }
        IMAGE_OUTPUT(const char *filename,IMAGE_FORMAT *format)
            { open(filename,format); }
        ~IMAGE_OUTPUT()
            { close(); }
     // open an image file:
        int open(const char *filename,IMAGE_FORMAT *format); 
     // close an image file:
        int close(void); 
     // see if capable of format:
        int capable(const IMAGE_FORMAT *format) 
            {
            if (ocapable[format->type()])
                return (*ocapable[format->type()])(format);
            else
                return 0;
             }   // write a number of scan lines to the image file
        unsigned int write(const unsigned char *buffer,
		unsigned int number_of_lines)

            {
            if (owrite[_format->type()])
                    return (*owrite[_format->type()])(&_file,
			_format,buffer,number_of_lines);
            return 0;
            }
        int bad(void)                  // image stream usable?
            { return _file.bad(); }
        int fail(void)                  // image stream error?
            { return _file.fail(); }
        int operator!()                // test stream for problems
            { return bad() || fail(); }
        const IMAGE_FORMAT *format(void)         // access format
            { return _format; }
    private:
        IMAGE_IO _file;                 // file/buffer output data
        IMAGE_FORMAT *_format;          // image format data
        // function pointers for the components
        static int (*oopen[MAX_TYPE])(IMAGE_IO *file,
                    IMAGE_FORMAT *format);
        static unsigned int (*owrite[MAX_TYPE])(IMAGE_IO *file,
                             IMAGE_FORMAT *format,const unsigned
                             char *buffer,unsigned int numlines);
        static int (*oclose[MAX_TYPE])(IMAGE_IO *file,
                    IMAGE_FORMAT *format);
        static int (*ocapable[MAX_TYPE])(const 
                    IMAGE_FORMAT *format);
    };
