r70: added imagefiles
[ctsim.git] / include / imagefile.h
1 #ifndef IDF_H
2 #define IDF_H
3
4 #include <string>
5 #include "kstddef.h"
6 #include <array2d.h>
7
8 using namespace std;
9
10 class Array2dFileLabel
11 {
12 private:
13     void init (void);
14
15 public:
16     kfloat64 calc_time;
17     kuint16 label_type;
18     kuint16 year;
19     kuint16 month;
20     kuint16 day;
21     kuint16 hour;
22     kuint16 minute;
23     kuint16 second;
24     string label_str;
25
26     static const int L_EMPTY = 0;
27     static const int L_HISTORY = 1;
28     static const int L_USER = 2;
29
30     Array2dFileLabel(); 
31
32     Array2dFileLabel(const char* const str, double ctime = 0.);
33
34     Array2dFileLabel(const int type, const char* const str, double ctime = 0.);
35
36     ~Array2dFileLabel();
37
38     const string& getLabelString (void) const
39         { return label_str; }
40
41     kfloat64 getCalcTime (void) const
42         { return calc_time; }
43
44     kfloat64 getLabelType (void) const
45         { return label_type; }
46
47     void getDateString (string& str) const;
48 };
49
50
51 template<class T>
52 class Array2dFile 
53 {
54 private:
55   void init (void);
56   kuint16 signature;
57   kuint16 num_labels;
58   kuint16 headersize;
59   string  filename;
60   int file_id;
61   iostream *io;
62   bool bHeaderWritten;
63   bool bDataWritten;
64
65   bool headerWrite (void);
66
67   bool headerRead (void);
68
69   bool arrayDataRead (void);
70
71   bool labelSeek (unsigned int label_num);
72
73 public:
74   kuint16 pixel_size;
75   kuint16 pixel_type;
76   kuint32 nx;
77   kuint32 ny;
78
79   kuint16 axis_increment_known;
80   kfloat64 xinc, yinc;
81   kuint16 axis_extent_known;
82   kfloat64 xmin, xmax, ymin, ymax;
83   kfloat64 pv_offset, pv_scale;
84
85   Array2d<T> *array;
86
87   static const int INT8 = 1;
88   static const int UINT8 = 2;
89   static const int INT16 = 3;
90   static const int UINT16 = 4;
91   static const int INT32 = 5;
92   static const int UINT32 = 6;
93   static const int FLOAT32 = 7;
94   static const int FLOAT64 = 8;
95
96   Array2dFile (unsigned int nx, unsigned int ny);
97   Array2dFile (const char* const filename);
98   Array2dFile (const char* const filename, unsigned int nx, unsigned int ny);
99   ~Array2dFile ();
100
101   virtual unsigned int getNumLabels (void) const
102   { return num_labels; }
103
104   bool labelRead (Array2dFileLabel& label, unsigned int label_num);
105
106   bool labelAdd (const char* const label_str, double calc_time=0.);
107
108   bool labelAdd (int type, const char* const label_str, double calc_time=0.);
109
110   void fileClose (void);
111
112   void set_axis_increment (double xinc, double yinc);
113
114   void set_axis_extent (double xmin, double xmax, double ymin, double ymax);
115
116   void get_pixel_extent (T& pvmin, T& pvmax);
117       
118   void set_pixel_offset_extent (double offset, double scale);
119
120   T** getArray (void) const
121       { return (array == NULL ? NULL : array->getArray()); }
122
123   bool arrayDataWrite (void);
124
125   bool fileRead (void);
126
127   bool fileCreate (void);
128
129   const string& GetFilename (void) const 
130       {  return filename; }
131 };
132
133
134 template<class T>
135 void
136 Array2dFile<T>::set_axis_increment (double xinc, double yinc)
137 {
138     axis_increment_known = true;
139     this.xinc = xinc;
140     this.yinc = yinc;
141 }
142
143 template<class T>
144 void 
145 Array2dFile<T>::set_axis_extent (double xmin, double xmax, double ymin, double ymax)
146 {
147     axis_extent_known = true;
148     this.xmin = xmin;
149     this.ymax = xmax;
150     this.xmin = xmin;
151     this.ymax = ymax;
152 }
153
154 template<class T>
155 void 
156 Array2dFile<T>::get_pixel_extent (T& pvmin, T& pvmax)
157 {
158       if (array != NULL) {
159         T** da = array.GetArray();
160         pvmax = pvmin = da[0][0];
161           for (int ix = 0; ix < nx; ix++)
162               for (int iy = 0; iy < ny; iy++)
163                   if (pvmax < da[ix][iy])
164                       pvmax = da[ix][iy];
165                   else if (pvmin > da[ix][iy])
166                     pvmin = da[ix][iy];
167       }
168 }
169
170 template<class T>
171 void
172 Array2dFile<T>::set_pixel_offset_extent (double offset, double scale)
173 {
174       pv_offset = offset;
175       pv_scale = scale;
176 }
177
178 template<class T>
179 void
180 Array2dFile<T>::init (void)
181 {
182   pixel_size = sizeof(T);
183   signature = ('I' * 256 + 'F');
184   file_id = -1;
185   nx = 0;
186   ny = 0;
187   headersize = 0;
188   num_labels = 0;
189   axis_increment_known = false;
190   axis_extent_known = false;
191   xinc = ymin = 0;
192   xmin = xmax = ymin = ymax = 0;
193   pv_offset = 0;
194   pv_scale = 1;
195   array = NULL;
196   io = NULL;
197
198 #if 0
199   const type_info& t_id = typeid(T);
200   cout << t_id.name() << endl;
201   const type_info& comp_id = typeid(T);
202
203   if (t_id == comp_id)
204       pixel_type = FLOAT64;
205   else if (t_id == typeid(kfloat32))
206     pixel_type = FLOAT32;
207   else if (t_id == typeid(kint32))
208     pixel_type = INT32;
209   else if (t_id == typeid(kuint32))
210     pixel_type = UINT32;
211   else if (t_id == typeid(kint16))
212     pixel_type = INT16;
213   else if (t_id == typeid(kuint16))
214     pixel_type = UINT16;
215   else if (t_id == typeid(kint8))
216     pixel_type = INT8;
217   else if (t_id == typeid(kuint8))
218     pixel_type = UINT8;
219   else
220 #endif
221       pixel_type = 0;
222
223   bHeaderWritten = false;
224   bDataWritten = false;
225 }
226
227 template<class T>
228 Array2dFile<T>::Array2dFile (unsigned int x, unsigned int y)
229 {
230     init();
231     nx = x;
232     ny = y;
233     array = new Array2d<T> (nx, ny);
234 }
235
236 template<class T>
237 Array2dFile<T>::Array2dFile (const char * const str, unsigned int x, unsigned int y)
238   : filename(str)
239 {
240     init();
241     nx = x;
242     ny = y;
243     array = new Array2d<T> (nx, ny);
244 }
245
246 template<class T>
247 Array2dFile<T>::Array2dFile (const char * const str)
248   : filename(str)
249 {
250     init();
251 }
252
253 template<class T>
254 bool
255 Array2dFile<T>::fileCreate (void)
256 {
257   //  io = new iostream(filename, ios::out | ios::in | ios::trunc | io::binary);
258     if ((file_id = open (filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
259         sys_error (ERR_WARNING, "Error opening file %s for writing [fileCreate]", filename.c_str());
260         return (false);
261     }
262   headerWrite();
263   return (true);
264 }
265
266 template<class T>
267 bool
268 Array2dFile<T>::fileRead (void)
269 {
270   // io = new iostream(filename, ios::out | ios::in | io::binary);
271   if ((file_id = open (filename.c_str(), O_RDONLY | O_BINARY)) < 0) {
272     sys_error (ERR_WARNING, "Unable to open file %s [fileRead]", filename.c_str());
273     return (false);
274   }
275
276   headerRead();
277   if (array != NULL)
278     delete array;
279
280   array = new Array2d<T> (nx, ny);
281
282   arrayDataRead();
283
284   return (true);
285 }
286
287 template<class T>
288 bool
289 Array2dFile<T>::headerRead (void)
290 {
291   if (file_id < 0) {
292     sys_error (ERR_WARNING, "Tried to read header with file closed [headerRead]");
293     return (false);
294   }
295
296   lseek (file_id, 0, SEEK_SET);
297   kuint16 file_signature;
298   kuint16 file_pixel_size;
299   kuint16 file_pixel_type;
300
301   read_nint16 (&headersize, file_id);
302   read_nint16 (&file_signature, file_id);
303   read_nint16 (&num_labels, file_id);
304   read_nint16 (&file_pixel_type, file_id);
305   read_nint16 (&file_pixel_size, file_id);
306   read_nint32 (&nx, file_id);
307   read_nint32 (&ny, file_id);
308   read_nint16 (&axis_increment_known, file_id);
309   read_nfloat64 (&xinc, file_id);
310   read_nfloat64 (&yinc, file_id);
311   read_nint16 (&axis_extent_known, file_id);
312   read_nfloat64 (&xmin, file_id);
313   read_nfloat64 (&xmax, file_id);
314   read_nfloat64 (&ymin, file_id);
315   read_nfloat64 (&ymax, file_id);
316   read_nfloat64 (&pv_offset, file_id);
317   read_nfloat64 (&pv_scale, file_id);
318
319   int read_headersize = lseek (file_id, 0, SEEK_CUR);
320   if (read_headersize != headersize) {
321     sys_error (ERR_WARNING, "Read headersize %d != file headersize %d", read_headersize, headersize);
322     return (false);
323   }
324   if (file_signature != signature) {
325     sys_error (ERR_WARNING, "File signature %d != true signature %d", file_signature, signature);
326     return (false);
327   }
328   if (file_pixel_type != pixel_type) {
329     sys_error (ERR_WARNING, "File pixel type %d != class pixel type %d", file_pixel_type, pixel_type);
330     return (false);
331   }
332   if (file_pixel_size != pixel_size) {
333     sys_error (ERR_WARNING, "File pixel size %d != class pixel size %d", file_pixel_size, pixel_size);
334     return (false);
335   }
336
337   return (true);
338 }
339
340 template<class T>
341 bool
342 Array2dFile<T>::headerWrite (void)
343 {
344   if (file_id < 0) {
345     sys_error (ERR_WARNING, "Tried to write header with file closed");
346     return (false);
347   }
348
349   lseek (file_id, 0, SEEK_SET);
350   write_nint16 (&headersize, file_id);
351   write_nint16 (&signature, file_id);
352   write_nint16 (&num_labels, file_id);
353   write_nint16 (&pixel_type, file_id);
354   write_nint16 (&pixel_size, file_id);
355   write_nint32 (&nx, file_id);
356   write_nint32 (&ny, file_id);
357   write_nint16 (&axis_increment_known, file_id);
358   write_nfloat64 (&xinc, file_id);
359   write_nfloat64 (&yinc, file_id);
360   write_nint16 (&axis_extent_known, file_id);
361   write_nfloat64 (&xmin, file_id);
362   write_nfloat64 (&xmax, file_id);
363   write_nfloat64 (&ymin, file_id);
364   write_nfloat64 (&ymax, file_id);
365   write_nfloat64 (&pv_offset, file_id);
366   write_nfloat64 (&pv_scale, file_id);
367
368   headersize = lseek (file_id, 0, SEEK_CUR);
369   lseek (file_id, 0, SEEK_SET);
370   write_nint16 (&headersize, file_id);
371   
372   return (true);
373 }
374
375 template<class T>
376 bool
377 Array2dFile<T>::arrayDataWrite (void)
378 {
379   if (file_id < 0) {
380     sys_error (ERR_WARNING, "Tried to arrayDataWrite with file_id < 0");
381     return (false);
382   }
383
384   lseek (file_id, headersize, SEEK_SET);
385   for (int ix = 0; ix < nx; ix++)
386     {
387       write (file_id, array->array_data[ix], ny * pixel_size);
388     }
389
390   return (true);
391 }
392
393 template<class T>
394 void
395 Array2dFile<T>::fileClose (void)
396 {
397   headerWrite ();
398   if (file_id >= 0 && array != NULL) {
399     arrayDataWrite ();
400     close (file_id);
401     file_id = -1;
402   }
403 }
404
405 template<class T>
406 Array2dFile<T>::~Array2dFile (void)
407 {
408     fileClose ();
409 }
410
411
412 template<class T>
413 bool
414 Array2dFile<T>::arrayDataRead (void)
415 {
416   if (file_id < 0) {
417     sys_error (ERR_WARNING, "Tried to arrayDataRead with file_id < 0");
418     return (false);
419   }
420
421   lseek (file_id, headersize, SEEK_SET);
422   for (int ix = 0; ix < nx; ix++) 
423     {
424       read (file_id, array->array_data[ix], ny * pixel_size);
425     }
426
427   return (true);
428 }
429
430 template<class T>
431 bool
432 Array2dFile<T>::labelSeek (unsigned int label_num)
433 {
434   if (label_num > num_labels) {
435     sys_error (ERR_WARNING, "label_num %d > num_labels %d [labelSeek]");
436     return (false);
437   }
438
439   if (array == NULL) {    // Could not have written data if array not allocated
440     sys_error (ERR_WARNING, "array == NULL [labelSeek]");
441     return (false);
442   }
443
444   off_t pos = headersize + array->sizeofArray();
445   if (lseek (file_id, pos, SEEK_SET) != pos) {
446     sys_error (ERR_WARNING, "Can't seek to end of data array");
447     return (false);
448   }
449
450   for (int i = 0; i < label_num; i++)
451       {
452           pos += 22;  // Skip to string length
453           if (lseek (file_id, pos, SEEK_SET) != pos) {
454             sys_error (ERR_WARNING, "Can't seek to string length");
455             return (false);
456           }
457           kuint16 strlength;
458           read_nint16 (&strlength, file_id);
459           pos += 2 + strlength;  // Skip label string length + data
460           if (lseek (file_id, pos, SEEK_SET) != pos) {
461             sys_error (ERR_WARNING, "Can't seek past label string");
462             return (false);
463           }
464       }
465
466   return (true);
467 }
468
469 template<class T>
470 bool
471 Array2dFile<T>::labelRead (Array2dFileLabel& label, unsigned int label_num)
472 {
473   if (label_num >= num_labels) {
474     sys_error (ERR_WARNING, "Trying to read past number of labels [labelRead]");
475     return (false);
476   }
477
478   if (! labelSeek (label_num)) {
479     sys_error (ERR_WARNING, "Error calling labelSeek");
480     return (false);
481   }
482
483   read_nint16 (&label.label_type, file_id);
484   read_nint16 (&label.year, file_id);
485   read_nint16 (&label.month, file_id);
486   read_nint16 (&label.day, file_id);
487   read_nint16 (&label.hour, file_id);
488   read_nint16 (&label.minute, file_id);
489   read_nint16 (&label.second, file_id);
490   read_nfloat64 (&label.calc_time, file_id);
491
492   kuint16 strlength;
493   read_nint16 (&strlength, file_id);
494   char *str = new char [strlength+1];
495   read (file_id, str, strlength);
496   label.label_str = str;
497
498   return (true);
499 }
500
501
502 template<class T>
503 bool
504 Array2dFile<T>::labelAdd (const char* const lstr, double calc_time=0.)
505 {
506   labelAdd (Array2dFileLabel::L_HISTORY, lstr, calc_time);
507 }
508
509 template<class T>
510 bool
511 Array2dFile<T>::labelAdd (int type, const char* const lstr, double calc_time=0.)
512 {
513   Array2dFileLabel label (type, lstr, calc_time);
514
515   labelSeek (num_labels);
516   
517   write_nint16 (&label.label_type, file_id);
518   write_nint16 (&label.year, file_id);
519   write_nint16 (&label.month, file_id);
520   write_nint16 (&label.day, file_id);
521   write_nint16 (&label.hour, file_id);
522   write_nint16 (&label.minute, file_id);
523   write_nint16 (&label.second, file_id);
524   write_nfloat64 (&label.calc_time, file_id);
525   kuint16 strlength = label.label_str.length();
526   write_nint16 (&strlength, file_id);
527   write (file_id, static_cast<const void*>(label.label_str.c_str()), strlength);
528
529   num_labels++;
530
531   headerWrite();
532   fsync(file_id);
533 }
534
535
536 #endif
537
538
539 class F32Image
540 {
541 public:
542   Array2dFile<kfloat32> idf;
543
544   F32Image (const char* const fname, unsigned int nx, unsigned int ny) : idf (fname, nx, ny)
545   {
546       idf.pixel_type = Array2dFile<kfloat32>::FLOAT32;
547   }
548
549   F32Image (unsigned int nx, unsigned int ny) : idf (nx, ny)
550   {
551       idf.pixel_type = Array2dFile<kfloat32>::FLOAT32;
552   }
553
554   F32Image (const char* const fname) : idf (fname)
555   {
556       idf.pixel_type = Array2dFile<kfloat32>::FLOAT32;
557   }
558 };
559
560 class F64Image 
561 {
562 public:
563   Array2dFile<kfloat64> idf;
564
565   F64Image (const char* const fname, unsigned int nx, unsigned int ny) : idf (fname, nx, ny)
566   {
567       idf.pixel_type = Array2dFile<kfloat64>::FLOAT64;
568   }
569
570   F64Image (unsigned int nx, unsigned int ny) : idf (nx, ny)
571   {
572       idf.pixel_type = Array2dFile<kfloat64>::FLOAT64;
573   }
574
575   F64Image (const char* const fname) : idf (fname)
576   {
577       idf.pixel_type = Array2dFile<kfloat64>::FLOAT64;
578   }
579 };
580
581 typedef F64Image ImageFile;
582
583