+#ifndef IDF_H
+#define IDF_H
+
+#include <string>
+#include "kstddef.h"
+#include <array2d.h>
+
+using namespace std;
+
+class Array2dFileLabel
+{
+private:
+ void init (void);
+
+public:
+ kfloat64 calc_time;
+ kuint16 label_type;
+ kuint16 year;
+ kuint16 month;
+ kuint16 day;
+ kuint16 hour;
+ kuint16 minute;
+ kuint16 second;
+ string label_str;
+
+ static const int L_EMPTY = 0;
+ static const int L_HISTORY = 1;
+ static const int L_USER = 2;
+
+ Array2dFileLabel();
+
+ Array2dFileLabel(const char* const str, double ctime = 0.);
+
+ Array2dFileLabel(const int type, const char* const str, double ctime = 0.);
+
+ ~Array2dFileLabel();
+
+ const string& getLabelString (void) const
+ { return label_str; }
+
+ kfloat64 getCalcTime (void) const
+ { return calc_time; }
+
+ kfloat64 getLabelType (void) const
+ { return label_type; }
+
+ void getDateString (string& str) const;
+};
+
+
+template<class T>
+class Array2dFile
+{
+private:
+ void init (void);
+ kuint16 signature;
+ kuint16 num_labels;
+ kuint16 headersize;
+ string filename;
+ int file_id;
+ iostream *io;
+ bool bHeaderWritten;
+ bool bDataWritten;
+
+ bool headerWrite (void);
+
+ bool headerRead (void);
+
+ bool arrayDataRead (void);
+
+ bool labelSeek (unsigned int label_num);
+
+public:
+ kuint16 pixel_size;
+ kuint16 pixel_type;
+ kuint32 nx;
+ kuint32 ny;
+
+ kuint16 axis_increment_known;
+ kfloat64 xinc, yinc;
+ kuint16 axis_extent_known;
+ kfloat64 xmin, xmax, ymin, ymax;
+ kfloat64 pv_offset, pv_scale;
+
+ Array2d<T> *array;
+
+ static const int INT8 = 1;
+ static const int UINT8 = 2;
+ static const int INT16 = 3;
+ static const int UINT16 = 4;
+ static const int INT32 = 5;
+ static const int UINT32 = 6;
+ static const int FLOAT32 = 7;
+ static const int FLOAT64 = 8;
+
+ Array2dFile (unsigned int nx, unsigned int ny);
+ Array2dFile (const char* const filename);
+ Array2dFile (const char* const filename, unsigned int nx, unsigned int ny);
+ ~Array2dFile ();
+
+ virtual unsigned int getNumLabels (void) const
+ { return num_labels; }
+
+ bool labelRead (Array2dFileLabel& label, unsigned int label_num);
+
+ bool labelAdd (const char* const label_str, double calc_time=0.);
+
+ bool labelAdd (int type, const char* const label_str, double calc_time=0.);
+
+ void fileClose (void);
+
+ void set_axis_increment (double xinc, double yinc);
+
+ void set_axis_extent (double xmin, double xmax, double ymin, double ymax);
+
+ void get_pixel_extent (T& pvmin, T& pvmax);
+
+ void set_pixel_offset_extent (double offset, double scale);
+
+ T** getArray (void) const
+ { return (array == NULL ? NULL : array->getArray()); }
+
+ bool arrayDataWrite (void);
+
+ bool fileRead (void);
+
+ bool fileCreate (void);
+
+ const string& GetFilename (void) const
+ { return filename; }
+};
+
+
+template<class T>
+void
+Array2dFile<T>::set_axis_increment (double xinc, double yinc)
+{
+ axis_increment_known = true;
+ this.xinc = xinc;
+ this.yinc = yinc;
+}
+
+template<class T>
+void
+Array2dFile<T>::set_axis_extent (double xmin, double xmax, double ymin, double ymax)
+{
+ axis_extent_known = true;
+ this.xmin = xmin;
+ this.ymax = xmax;
+ this.xmin = xmin;
+ this.ymax = ymax;
+}
+
+template<class T>
+void
+Array2dFile<T>::get_pixel_extent (T& pvmin, T& pvmax)
+{
+ if (array != NULL) {
+ T** da = array.GetArray();
+ pvmax = pvmin = da[0][0];
+ for (int ix = 0; ix < nx; ix++)
+ for (int iy = 0; iy < ny; iy++)
+ if (pvmax < da[ix][iy])
+ pvmax = da[ix][iy];
+ else if (pvmin > da[ix][iy])
+ pvmin = da[ix][iy];
+ }
+}
+
+template<class T>
+void
+Array2dFile<T>::set_pixel_offset_extent (double offset, double scale)
+{
+ pv_offset = offset;
+ pv_scale = scale;
+}
+
+template<class T>
+void
+Array2dFile<T>::init (void)
+{
+ pixel_size = sizeof(T);
+ signature = ('I' * 256 + 'F');
+ file_id = -1;
+ nx = 0;
+ ny = 0;
+ headersize = 0;
+ num_labels = 0;
+ axis_increment_known = false;
+ axis_extent_known = false;
+ xinc = ymin = 0;
+ xmin = xmax = ymin = ymax = 0;
+ pv_offset = 0;
+ pv_scale = 1;
+ array = NULL;
+ io = NULL;
+
+#if 0
+ const type_info& t_id = typeid(T);
+ cout << t_id.name() << endl;
+ const type_info& comp_id = typeid(T);
+
+ if (t_id == comp_id)
+ pixel_type = FLOAT64;
+ else if (t_id == typeid(kfloat32))
+ pixel_type = FLOAT32;
+ else if (t_id == typeid(kint32))
+ pixel_type = INT32;
+ else if (t_id == typeid(kuint32))
+ pixel_type = UINT32;
+ else if (t_id == typeid(kint16))
+ pixel_type = INT16;
+ else if (t_id == typeid(kuint16))
+ pixel_type = UINT16;
+ else if (t_id == typeid(kint8))
+ pixel_type = INT8;
+ else if (t_id == typeid(kuint8))
+ pixel_type = UINT8;
+ else
+#endif
+ pixel_type = 0;
+
+ bHeaderWritten = false;
+ bDataWritten = false;
+}
+
+template<class T>
+Array2dFile<T>::Array2dFile (unsigned int x, unsigned int y)
+{
+ init();
+ nx = x;
+ ny = y;
+ array = new Array2d<T> (nx, ny);
+}
+
+template<class T>
+Array2dFile<T>::Array2dFile (const char * const str, unsigned int x, unsigned int y)
+ : filename(str)
+{
+ init();
+ nx = x;
+ ny = y;
+ array = new Array2d<T> (nx, ny);
+}
+
+template<class T>
+Array2dFile<T>::Array2dFile (const char * const str)
+ : filename(str)
+{
+ init();
+}
+
+template<class T>
+bool
+Array2dFile<T>::fileCreate (void)
+{
+ // io = new iostream(filename, ios::out | ios::in | ios::trunc | io::binary);
+ if ((file_id = open (filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+ sys_error (ERR_WARNING, "Error opening file %s for writing [fileCreate]", filename.c_str());
+ return (false);
+ }
+ headerWrite();
+ return (true);
+}
+
+template<class T>
+bool
+Array2dFile<T>::fileRead (void)
+{
+ // io = new iostream(filename, ios::out | ios::in | io::binary);
+ if ((file_id = open (filename.c_str(), O_RDONLY | O_BINARY)) < 0) {
+ sys_error (ERR_WARNING, "Unable to open file %s [fileRead]", filename.c_str());
+ return (false);
+ }
+
+ headerRead();
+ if (array != NULL)
+ delete array;
+
+ array = new Array2d<T> (nx, ny);
+
+ arrayDataRead();
+
+ return (true);
+}
+
+template<class T>
+bool
+Array2dFile<T>::headerRead (void)
+{
+ if (file_id < 0) {
+ sys_error (ERR_WARNING, "Tried to read header with file closed [headerRead]");
+ return (false);
+ }
+
+ lseek (file_id, 0, SEEK_SET);
+ kuint16 file_signature;
+ kuint16 file_pixel_size;
+ kuint16 file_pixel_type;
+
+ read_nint16 (&headersize, file_id);
+ read_nint16 (&file_signature, file_id);
+ read_nint16 (&num_labels, file_id);
+ read_nint16 (&file_pixel_type, file_id);
+ read_nint16 (&file_pixel_size, file_id);
+ read_nint32 (&nx, file_id);
+ read_nint32 (&ny, file_id);
+ read_nint16 (&axis_increment_known, file_id);
+ read_nfloat64 (&xinc, file_id);
+ read_nfloat64 (&yinc, file_id);
+ read_nint16 (&axis_extent_known, file_id);
+ read_nfloat64 (&xmin, file_id);
+ read_nfloat64 (&xmax, file_id);
+ read_nfloat64 (&ymin, file_id);
+ read_nfloat64 (&ymax, file_id);
+ read_nfloat64 (&pv_offset, file_id);
+ read_nfloat64 (&pv_scale, file_id);
+
+ int read_headersize = lseek (file_id, 0, SEEK_CUR);
+ if (read_headersize != headersize) {
+ sys_error (ERR_WARNING, "Read headersize %d != file headersize %d", read_headersize, headersize);
+ return (false);
+ }
+ if (file_signature != signature) {
+ sys_error (ERR_WARNING, "File signature %d != true signature %d", file_signature, signature);
+ return (false);
+ }
+ if (file_pixel_type != pixel_type) {
+ sys_error (ERR_WARNING, "File pixel type %d != class pixel type %d", file_pixel_type, pixel_type);
+ return (false);
+ }
+ if (file_pixel_size != pixel_size) {
+ sys_error (ERR_WARNING, "File pixel size %d != class pixel size %d", file_pixel_size, pixel_size);
+ return (false);
+ }
+
+ return (true);
+}
+
+template<class T>
+bool
+Array2dFile<T>::headerWrite (void)
+{
+ if (file_id < 0) {
+ sys_error (ERR_WARNING, "Tried to write header with file closed");
+ return (false);
+ }
+
+ lseek (file_id, 0, SEEK_SET);
+ write_nint16 (&headersize, file_id);
+ write_nint16 (&signature, file_id);
+ write_nint16 (&num_labels, file_id);
+ write_nint16 (&pixel_type, file_id);
+ write_nint16 (&pixel_size, file_id);
+ write_nint32 (&nx, file_id);
+ write_nint32 (&ny, file_id);
+ write_nint16 (&axis_increment_known, file_id);
+ write_nfloat64 (&xinc, file_id);
+ write_nfloat64 (&yinc, file_id);
+ write_nint16 (&axis_extent_known, file_id);
+ write_nfloat64 (&xmin, file_id);
+ write_nfloat64 (&xmax, file_id);
+ write_nfloat64 (&ymin, file_id);
+ write_nfloat64 (&ymax, file_id);
+ write_nfloat64 (&pv_offset, file_id);
+ write_nfloat64 (&pv_scale, file_id);
+
+ headersize = lseek (file_id, 0, SEEK_CUR);
+ lseek (file_id, 0, SEEK_SET);
+ write_nint16 (&headersize, file_id);
+
+ return (true);
+}
+
+template<class T>
+bool
+Array2dFile<T>::arrayDataWrite (void)
+{
+ if (file_id < 0) {
+ sys_error (ERR_WARNING, "Tried to arrayDataWrite with file_id < 0");
+ return (false);
+ }
+
+ lseek (file_id, headersize, SEEK_SET);
+ for (int ix = 0; ix < nx; ix++)
+ {
+ write (file_id, array->array_data[ix], ny * pixel_size);
+ }
+
+ return (true);
+}
+
+template<class T>
+void
+Array2dFile<T>::fileClose (void)
+{
+ headerWrite ();
+ if (file_id >= 0 && array != NULL) {
+ arrayDataWrite ();
+ close (file_id);
+ file_id = -1;
+ }
+}
+
+template<class T>
+Array2dFile<T>::~Array2dFile (void)
+{
+ fileClose ();
+}
+
+
+template<class T>
+bool
+Array2dFile<T>::arrayDataRead (void)
+{
+ if (file_id < 0) {
+ sys_error (ERR_WARNING, "Tried to arrayDataRead with file_id < 0");
+ return (false);
+ }
+
+ lseek (file_id, headersize, SEEK_SET);
+ for (int ix = 0; ix < nx; ix++)
+ {
+ read (file_id, array->array_data[ix], ny * pixel_size);
+ }
+
+ return (true);
+}
+
+template<class T>
+bool
+Array2dFile<T>::labelSeek (unsigned int label_num)
+{
+ if (label_num > num_labels) {
+ sys_error (ERR_WARNING, "label_num %d > num_labels %d [labelSeek]");
+ return (false);
+ }
+
+ if (array == NULL) { // Could not have written data if array not allocated
+ sys_error (ERR_WARNING, "array == NULL [labelSeek]");
+ return (false);
+ }
+
+ off_t pos = headersize + array->sizeofArray();
+ if (lseek (file_id, pos, SEEK_SET) != pos) {
+ sys_error (ERR_WARNING, "Can't seek to end of data array");
+ return (false);
+ }
+
+ for (int i = 0; i < label_num; i++)
+ {
+ pos += 22; // Skip to string length
+ if (lseek (file_id, pos, SEEK_SET) != pos) {
+ sys_error (ERR_WARNING, "Can't seek to string length");
+ return (false);
+ }
+ kuint16 strlength;
+ read_nint16 (&strlength, file_id);
+ pos += 2 + strlength; // Skip label string length + data
+ if (lseek (file_id, pos, SEEK_SET) != pos) {
+ sys_error (ERR_WARNING, "Can't seek past label string");
+ return (false);
+ }
+ }
+
+ return (true);
+}
+
+template<class T>
+bool
+Array2dFile<T>::labelRead (Array2dFileLabel& label, unsigned int label_num)
+{
+ if (label_num >= num_labels) {
+ sys_error (ERR_WARNING, "Trying to read past number of labels [labelRead]");
+ return (false);
+ }
+
+ if (! labelSeek (label_num)) {
+ sys_error (ERR_WARNING, "Error calling labelSeek");
+ return (false);
+ }
+
+ read_nint16 (&label.label_type, file_id);
+ read_nint16 (&label.year, file_id);
+ read_nint16 (&label.month, file_id);
+ read_nint16 (&label.day, file_id);
+ read_nint16 (&label.hour, file_id);
+ read_nint16 (&label.minute, file_id);
+ read_nint16 (&label.second, file_id);
+ read_nfloat64 (&label.calc_time, file_id);
+
+ kuint16 strlength;
+ read_nint16 (&strlength, file_id);
+ char *str = new char [strlength+1];
+ read (file_id, str, strlength);
+ label.label_str = str;
+
+ return (true);
+}
+
+
+template<class T>
+bool
+Array2dFile<T>::labelAdd (const char* const lstr, double calc_time=0.)
+{
+ labelAdd (Array2dFileLabel::L_HISTORY, lstr, calc_time);
+}
+
+template<class T>
+bool
+Array2dFile<T>::labelAdd (int type, const char* const lstr, double calc_time=0.)
+{
+ Array2dFileLabel label (type, lstr, calc_time);
+
+ labelSeek (num_labels);
+
+ write_nint16 (&label.label_type, file_id);
+ write_nint16 (&label.year, file_id);
+ write_nint16 (&label.month, file_id);
+ write_nint16 (&label.day, file_id);
+ write_nint16 (&label.hour, file_id);
+ write_nint16 (&label.minute, file_id);
+ write_nint16 (&label.second, file_id);
+ write_nfloat64 (&label.calc_time, file_id);
+ kuint16 strlength = label.label_str.length();
+ write_nint16 (&strlength, file_id);
+ write (file_id, static_cast<const void*>(label.label_str.c_str()), strlength);
+
+ num_labels++;
+
+ headerWrite();
+ fsync(file_id);
+}
+
+
+#endif
+
+
+class F32Image
+{
+public:
+ Array2dFile<kfloat32> idf;
+
+ F32Image (const char* const fname, unsigned int nx, unsigned int ny) : idf (fname, nx, ny)
+ {
+ idf.pixel_type = Array2dFile<kfloat32>::FLOAT32;
+ }
+
+ F32Image (unsigned int nx, unsigned int ny) : idf (nx, ny)
+ {
+ idf.pixel_type = Array2dFile<kfloat32>::FLOAT32;
+ }
+
+ F32Image (const char* const fname) : idf (fname)
+ {
+ idf.pixel_type = Array2dFile<kfloat32>::FLOAT32;
+ }
+};
+
+class F64Image
+{
+public:
+ Array2dFile<kfloat64> idf;
+
+ F64Image (const char* const fname, unsigned int nx, unsigned int ny) : idf (fname, nx, ny)
+ {
+ idf.pixel_type = Array2dFile<kfloat64>::FLOAT64;
+ }
+
+ F64Image (unsigned int nx, unsigned int ny) : idf (nx, ny)
+ {
+ idf.pixel_type = Array2dFile<kfloat64>::FLOAT64;
+ }
+
+ F64Image (const char* const fname) : idf (fname)
+ {
+ idf.pixel_type = Array2dFile<kfloat64>::FLOAT64;
+ }
+};
+
+typedef F64Image ImageFile;
+
+