r593: no message
[ctsim.git] / libctsim / imagefile.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:           imagefile.cpp
5 **  Purpose:      Imagefile classes
6 **      Programmer:   Kevin Rosenberg
7 **      Date Started: June 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (c) 1983-2001 Kevin Rosenberg
11 **
12 **  $Id: imagefile.cpp,v 1.39 2001/03/02 02:08:14 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "ct.h"
29
30 const double ImageFile::s_dRedGrayscaleFactor = 0.299;
31 const double ImageFile::s_dGreenGrayscaleFactor = 0.587;
32 const double ImageFile::s_dBlueGrayscaleFactor = 0.114;
33
34
35 const int ImageFile::EXPORT_FORMAT_INVALID = -1;
36 const int ImageFile::EXPORT_FORMAT_PGM = 0;
37 const int ImageFile::EXPORT_FORMAT_PGMASCII = 1;
38 #ifdef HAVE_PNG
39 const int ImageFile::EXPORT_FORMAT_PNG = 2;
40 const int ImageFile::EXPORT_FORMAT_PNG16 = 3;
41 #endif
42 #ifdef HAVE_CTN_DICOM
43 const int ImageFile::EXPORT_FORMAT_DICOM = 4;
44 #endif
45
46 const char* ImageFile::s_aszExportFormatName[] = 
47 {
48   {"pgm"},
49   {"pgmascii"},
50 #ifdef HAVE_PNG
51   {"png"},
52   {"png16"},
53 #endif
54 #ifdef HAVE_CTN_DICOM
55   {"dicom"},
56 #endif
57 };
58
59 const char* ImageFile::s_aszExportFormatTitle[] = 
60 {
61   {"PGM"},
62   {"PGM ASCII"},
63   {"PNG"},
64   {"PNG 16-bit"},
65 #ifdef HAVE_CTN_DICOM
66   {"Dicom"},
67 #endif
68 };
69 const int ImageFile::s_iExportFormatCount = sizeof(s_aszExportFormatName) / sizeof(const char*);
70
71
72 const int ImageFile::IMPORT_FORMAT_INVALID = -1;
73 const int ImageFile::IMPORT_FORMAT_PPM = 0;
74 #ifdef HAVE_PNG
75 const int ImageFile::IMPORT_FORMAT_PNG = 1;
76 #endif
77 #ifdef HAVE_CTN_DICOM
78 const int ImageFile::IMPORT_FORMAT_DICOM = 2;
79 #endif
80
81
82 const char* ImageFile::s_aszImportFormatName[] = 
83 {
84   {"ppm"},
85 #ifdef HAVE_PNG
86   {"png"},
87 #endif
88 #ifdef HAVE_CTN_DICOM
89   {"dicom"},
90 #endif
91 };
92
93 const char* ImageFile::s_aszImportFormatTitle[] = 
94 {
95   {"PPM"},
96   {"PNG"},
97 #ifdef HAVE_CTN_DICOM
98   {"Dicom"},
99 #endif
100 };
101 const int ImageFile::s_iImportFormatCount = sizeof(s_aszImportFormatName) / sizeof(const char*);
102
103
104
105 F32Image::F32Image (int nx, int ny, int dataType)
106 : Array2dFile (nx, ny, sizeof(kfloat32), Array2dFile::PIXEL_FLOAT32, dataType)
107 {
108 }
109
110 F32Image::F32Image (void)
111 : Array2dFile()
112 {
113   setPixelFormat (Array2dFile::PIXEL_FLOAT32);
114   setPixelSize (sizeof(kfloat32));
115   setDataType (Array2dFile::DATA_TYPE_REAL);
116 }
117
118 F64Image::F64Image (int nx, int ny, int dataType)
119 : Array2dFile (nx, ny, sizeof(kfloat64), Array2dFile::PIXEL_FLOAT64, dataType)
120 {
121 }
122
123 F64Image::F64Image (void)
124 : Array2dFile ()
125 {
126   setPixelFormat (PIXEL_FLOAT64);
127   setPixelSize (sizeof(kfloat64));
128   setDataType (Array2dFile::DATA_TYPE_REAL);
129 }
130
131 void 
132 ImageFile::getCenterCoordinates (unsigned int& iXCenter, unsigned int& iYCenter)
133 {
134   if (isEven (m_nx))
135     iXCenter = m_nx / 2;
136   else
137     iXCenter = (m_nx - 1) / 2;
138   
139   if (isEven (m_ny))
140     iYCenter = m_ny / 2;
141   else
142     iYCenter = (m_ny - 1) / 2;
143 }
144
145
146 void 
147 ImageFile::filterResponse (const char* const domainName, double bw, const char* const filterName, double filt_param, double dInputScale, double dOutputScale)
148 {
149   ImageFileArray v = getArray();
150   SignalFilter filter (filterName, domainName, bw, filt_param);
151   
152   unsigned int iXCenter, iYCenter;
153   getCenterCoordinates (iXCenter, iYCenter);
154   
155   for (unsigned int ix = 0; ix < m_nx; ix++)
156     for (unsigned int iy = 0; iy < m_ny; iy++) {
157       long lD2 = ((ix - iXCenter) * (ix - iXCenter)) + ((iy - iYCenter) * (iy - iYCenter));
158       double r = ::sqrt (static_cast<double>(lD2)) * dInputScale;
159       v[ix][iy] = filter.response (r) * dOutputScale;
160     }
161 }
162
163 int
164 ImageFile::display (void) const
165 {
166   double pmin, pmax;
167   
168   getMinMax (pmin, pmax);
169   
170   return (displayScaling (1, pmin, pmax));
171 }
172
173 int 
174 ImageFile::displayScaling (const int scale, const ImageFileValue pmin, const ImageFileValue pmax) const
175 {
176   int nx = m_nx;
177   int ny = m_ny;
178   ImageFileArrayConst v = getArray();
179   if (v == NULL || nx == 0 || ny == 0)
180     return 0;
181   
182 #if HAVE_G2_H
183   int* pPens = new int [nx * ny * scale * scale ];
184   
185   double view_scale = 255 / (pmax - pmin);
186   int id_X11 = g2_open_X11 (nx * scale, ny * scale);
187   int grayscale[256];
188   for (int i = 0; i < 256; i++) {
189     double cval = i / 255.;
190     grayscale[i] = g2_ink (id_X11, cval, cval, cval);
191   }
192   
193   for (int iy = ny - 1; iy >= 0; iy--) {
194     int iRowPos = ((ny - 1 - iy) * scale) * (nx * scale);
195     for (int ix = 0; ix < nx; ix++) {
196       int cval = static_cast<int>((v[ix][iy] - pmin) * view_scale);
197       if (cval < 0)  
198         cval = 0;
199       else if (cval > 255) 
200         cval = 255;
201       for (int sy = 0; sy < scale; sy++)
202         for (int sx = 0; sx < scale; sx++)
203           pPens[iRowPos+(sy * nx * scale)+(sx + (ix * scale))] = grayscale[cval];
204     }
205   }
206   
207   g2_image (id_X11, 0., 0., nx * scale, ny * scale, pPens);
208   
209   delete pPens;
210   return (id_X11);
211 #else
212   return 0;
213 #endif
214 }
215
216
217
218 // ImageFile::comparativeStatistics    Calculate comparative stats
219 //
220 // OUTPUT
221 //   d   Normalized root mean squared distance measure
222 //   r   Normalized mean absolute distance measure
223 //   e   Worst case distance measure
224 //
225 // REFERENCES
226 //  G.T. Herman, Image Reconstruction From Projections, 1980
227
228 bool
229 ImageFile::comparativeStatistics (const ImageFile& imComp, double& d, double& r, double& e) const
230 {
231   if (imComp.nx() != m_nx && imComp.ny() != m_ny) {
232     sys_error (ERR_WARNING, "Image sizes differ [ImageFile::comparativeStatistics]");
233     return false;
234   }
235   ImageFileArrayConst v = getArray();
236   if (v == NULL || m_nx == 0 || m_ny == 0)
237     return false;
238   
239   ImageFileArrayConst vComp = imComp.getArray();
240   
241   double myMean = 0.;
242   for (unsigned int ix = 0; ix < m_nx; ix++) {
243     for (unsigned int iy = 0; iy < m_ny; iy++) {
244       myMean += v[ix][iy];
245     }
246   }
247   myMean /= (m_nx * m_ny);
248   
249   double sqErrorSum = 0.;
250   double absErrorSum = 0.;
251   double sqDiffFromMeanSum = 0.;
252   double absValueSum = 0.;
253   for (unsigned int ix2 = 0; ix2 < m_nx; ix2++) {
254     for (unsigned int iy = 0; iy < m_ny; iy++) {
255       double diff = v[ix2][iy] - vComp[ix2][iy];
256       sqErrorSum += diff * diff;
257       absErrorSum += fabs(diff);
258       double diffFromMean = v[ix2][iy] - myMean;
259       sqDiffFromMeanSum += diffFromMean * diffFromMean;
260       absValueSum += fabs(v[ix2][iy]);
261     }
262   }
263   
264   d = ::sqrt (sqErrorSum / sqDiffFromMeanSum);
265   r = absErrorSum / absValueSum;
266   
267   int hx = m_nx / 2;
268   int hy = m_ny / 2;
269   double eMax = -1;
270   for (int ix3 = 0; ix3 < hx; ix3++) {
271     for (int iy = 0; iy < hy; iy++) {
272       double avgPixel = 0.25 * (v[2*ix3][2*iy] + v[2*ix3+1][2*iy] + v[2*ix3][2*iy+1] + v[2*ix3+1][2*iy+1]);
273       double avgPixelComp = 0.25 * (vComp[2*ix3][2*iy] + vComp[2*ix3+1][2*iy] + vComp[2*ix3][2*iy+1] + vComp[2*ix3+1][2*iy+1]);
274       double error = fabs (avgPixel - avgPixelComp);
275       if (error > eMax)
276         eMax = error;
277     }
278   }
279   
280   e = eMax;
281   
282   return true;
283 }
284
285
286 bool
287 ImageFile::printComparativeStatistics (const ImageFile& imComp, std::ostream& os) const
288 {
289   double d, r, e;
290   
291   if (comparativeStatistics (imComp, d, r, e)) {
292     os << "  Normalized root mean squared distance (d): " << d << std::endl;
293     os << "      Normalized mean absolute distance (r): " << r << std::endl;
294     os << "Worst case distance (2x2 pixel average) (e): " << e << std::endl;
295     return true;
296   }
297   return false;
298 }
299
300
301 void
302 ImageFile::printStatistics (std::ostream& os) const
303 {
304   double min, max, mean, mode, median, stddev;
305   
306   statistics (min, max, mean, mode, median, stddev);
307   if (isComplex())
308     os << "Real Component Statistics" << std::endl;
309   
310   os << "   min: " << min << std::endl;
311   os << "   max: " << max << std::endl;
312   os << "  mean: " << mean << std::endl;
313   os << "  mode: " << mode << std::endl;
314   os << "median: " << median << std::endl;
315   os << "stddev: " << stddev << std::endl;
316   
317   if (isComplex()) {
318     statistics (getImaginaryArray(), min, max, mean, mode, median, stddev);
319     os << std::endl << "Imaginary Component Statistics" << std::endl;
320     os << "   min: " << min << std::endl;
321     os << "   max: " << max << std::endl;
322     os << "  mean: " << mean << std::endl;
323     os << "  mode: " << mode << std::endl;
324     os << "median: " << median << std::endl;
325     os << "stddev: " << stddev << std::endl;
326   }
327 }
328
329
330 void
331 ImageFile::statistics (double& min, double& max, double& mean, double& mode, double& median, double& stddev) const
332 {
333   ImageFileArrayConst v = getArray();
334   statistics (v, min, max, mean, mode, median, stddev);
335 }
336
337
338 void
339 ImageFile::statistics (ImageFileArrayConst v, double& min, double& max, double& mean, double& mode, double& median, double& stddev) const
340 {
341   int nx = m_nx;
342   int ny = m_ny;
343   
344   if (v == NULL || nx == 0 || ny == 0)
345     return;
346   
347   std::vector<double> vecImage;
348   int iVec = 0;
349   vecImage.resize (nx * ny);
350   for (int ix = 0; ix < nx; ix++) {
351     for (int iy = 0; iy < ny; iy++)
352       vecImage[iVec++] = v[ix][iy];
353   }
354   
355   vectorNumericStatistics (vecImage, nx * ny, min, max, mean, mode, median, stddev);
356 }
357
358 void
359 ImageFile::getMinMax (double& min, double& max) const
360 {
361   int nx = m_nx;
362   int ny = m_ny;
363   ImageFileArrayConst v = getArray();
364   
365   if (v == NULL || nx == 0 || ny == 0)
366     return;
367   
368   min = v[0][0];
369   max = v[0][0];
370   for (int ix = 0; ix < nx; ix++) {
371     for (int iy = 0; iy < ny; iy++) {
372       if (v[ix][iy] > max)
373         max = v[ix][iy];
374       if (v[ix][iy] < min)
375         min = v[ix][iy];
376     }
377   }
378 }
379
380 bool
381 ImageFile::convertRealToComplex ()
382 {
383   if (dataType() != Array2dFile::DATA_TYPE_REAL)
384     return false;
385   
386   if (! reallocRealToComplex())
387     return false;
388   
389   ImageFileArray vImag = getImaginaryArray();
390   for (unsigned int ix = 0; ix < m_nx; ix++) {
391     ImageFileColumn vCol = vImag[ix];
392     for (unsigned int iy = 0; iy < m_ny; iy++)
393       *vCol++ = 0;
394   }
395   
396   return true;
397 }
398
399 bool
400 ImageFile::convertComplexToReal ()
401 {
402   if (dataType() != Array2dFile::DATA_TYPE_COMPLEX)
403     return false;
404   
405   ImageFileArray vReal = getArray();
406   ImageFileArray vImag = getImaginaryArray();
407   for (unsigned int ix = 0; ix < m_nx; ix++) {
408     ImageFileColumn vRealCol = vReal[ix];
409     ImageFileColumn vImagCol = vImag[ix];
410     for (unsigned int iy = 0; iy < m_ny; iy++) {
411       CTSimComplex c (*vRealCol, *vImagCol);
412       *vRealCol++ = std::abs (c);
413       vImagCol++;
414     }
415   }
416   
417   return reallocComplexToReal();
418 }
419
420 bool
421 ImageFile::subtractImages (const ImageFile& rRHS, ImageFile& result) const
422 {
423   if (m_nx != rRHS.nx() || m_ny != rRHS.ny() || m_nx != result.nx() || m_ny != result.ny()) {
424     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::subtractImage]");
425     return false;
426   }
427   
428   if (isComplex() || rRHS.isComplex() && ! result.isComplex())
429     result.convertRealToComplex();
430   
431   ImageFileArrayConst vLHS = getArray();
432   ImageFileArrayConst vLHSImag = getImaginaryArray();
433   ImageFileArrayConst vRHS = rRHS.getArray();
434   ImageFileArrayConst vRHSImag = rRHS.getImaginaryArray();
435   ImageFileArray vResult = result.getArray();
436   ImageFileArray vResultImag = result.getImaginaryArray();
437   
438   for (unsigned int ix = 0; ix < m_nx; ix++) {
439     for (unsigned int iy = 0; iy < m_ny; iy++) {
440       vResult[ix][iy] = vLHS[ix][iy] - vRHS[ix][iy];
441       if (result.isComplex()) {
442         vResultImag[ix][iy] = 0;
443         if (isComplex())
444           vResultImag[ix][iy] += vLHSImag[ix][iy];
445         if (rRHS.isComplex())
446           vResultImag[ix][iy] -= vRHSImag[ix][iy];
447       }
448     }
449   }
450   
451   return true;
452 }
453
454 bool
455 ImageFile::addImages (const ImageFile& rRHS, ImageFile& result) const
456 {
457   if (m_nx != rRHS.nx() || m_ny != rRHS.ny() || m_nx != result.nx() || m_ny != result.ny()) {
458     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::subtractImage]");
459     return false;
460   }
461   
462   if (isComplex() || rRHS.isComplex() && ! result.isComplex())
463     result.convertRealToComplex();
464   
465   ImageFileArrayConst vLHS = getArray();
466   ImageFileArrayConst vLHSImag = getImaginaryArray();
467   ImageFileArrayConst vRHS = rRHS.getArray();
468   ImageFileArrayConst vRHSImag = rRHS.getImaginaryArray();
469   ImageFileArray vResult = result.getArray();
470   ImageFileArray vResultImag = result.getImaginaryArray();
471   
472   for (unsigned int ix = 0; ix < m_nx; ix++) {
473     for (unsigned int iy = 0; iy < m_ny; iy++) {
474       vResult[ix][iy] = vLHS[ix][iy] + vRHS[ix][iy];
475       if (result.isComplex()) {
476         vResultImag[ix][iy] = 0;
477         if (isComplex())
478           vResultImag[ix][iy] += vLHSImag[ix][iy];
479         if (rRHS.isComplex())
480           vResultImag[ix][iy] += vRHSImag[ix][iy];
481       }
482     }
483   }
484   
485   return true;
486 }
487
488 bool
489 ImageFile::multiplyImages (const ImageFile& rRHS, ImageFile& result) const
490 {
491   if (m_nx != rRHS.nx() || m_ny != rRHS.ny() || m_nx != result.nx() || m_ny != result.ny()) {
492     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::subtractImage]");
493     return false;
494   }
495   
496   if (isComplex() || rRHS.isComplex() && ! result.isComplex())
497     result.convertRealToComplex();
498   
499   ImageFileArrayConst vLHS = getArray();
500   ImageFileArrayConst vLHSImag = getImaginaryArray();
501   ImageFileArrayConst vRHS = rRHS.getArray();
502   ImageFileArrayConst vRHSImag = rRHS.getImaginaryArray();
503   ImageFileArray vResult = result.getArray();
504   ImageFileArray vResultImag = result.getImaginaryArray();
505   
506   for (unsigned int ix = 0; ix < m_nx; ix++) {
507     for (unsigned int iy = 0; iy < m_ny; iy++) {
508       if (result.isComplex()) {
509         double dImag = 0;
510         if (isComplex())
511           dImag = vLHSImag[ix][iy];
512         std::complex<double> cLHS (vLHS[ix][iy], dImag);
513         dImag = 0;
514         if (rRHS.isComplex())
515           dImag = vRHSImag[ix][iy];
516         std::complex<double> cRHS (vRHS[ix][iy], dImag);
517         std::complex<double> cResult = cLHS * cRHS;
518         vResult[ix][iy] = cResult.real();
519         vResultImag[ix][iy] = cResult.imag();
520       } else
521         vResult[ix][iy] = vLHS[ix][iy] * vRHS[ix][iy];
522     }
523   }
524   
525   
526   return true;
527 }
528
529 bool
530 ImageFile::divideImages (const ImageFile& rRHS, ImageFile& result) const
531 {
532   if (m_nx != rRHS.nx() || m_ny != rRHS.ny() || m_nx != result.nx() || m_ny != result.ny()) {
533     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::subtractImage]");
534     return false;
535   }
536   
537   if (isComplex() || rRHS.isComplex() && ! result.isComplex())
538     result.convertRealToComplex();
539   
540   ImageFileArrayConst vLHS = getArray();
541   ImageFileArrayConst vLHSImag = getImaginaryArray();
542   ImageFileArrayConst vRHS = rRHS.getArray();
543   ImageFileArrayConst vRHSImag = rRHS.getImaginaryArray();
544   ImageFileArray vResult = result.getArray();
545   ImageFileArray vResultImag = result.getImaginaryArray();
546   
547   for (unsigned int ix = 0; ix < m_nx; ix++) {
548     for (unsigned int iy = 0; iy < m_ny; iy++) {
549       if (result.isComplex()) {
550         double dImag = 0;
551         if (isComplex())
552           dImag = vLHSImag[ix][iy];
553         std::complex<double> cLHS (vLHS[ix][iy], dImag);
554         dImag = 0;
555         if (rRHS.isComplex())
556           dImag = vRHSImag[ix][iy];
557         std::complex<double> cRHS (vRHS[ix][iy], dImag);
558         std::complex<double> cResult = cLHS / cRHS;
559         vResult[ix][iy] = cResult.real();
560         vResultImag[ix][iy] = cResult.imag();
561       } else {
562         if (vRHS != 0)
563           vResult[ix][iy] = vLHS[ix][iy] / vRHS[ix][iy];
564         else
565           vResult[ix][iy] = 0;
566       }
567     }
568   }
569   
570   return true;
571 }
572
573
574 bool
575 ImageFile::invertPixelValues (ImageFile& result) const
576 {
577   if (m_nx != result.nx() || m_ny != result.ny()) {
578     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
579     return false;
580   }
581   
582   if (isComplex() && ! result.isComplex())
583     result.convertRealToComplex();
584   
585   ImageFileArrayConst vLHS = getArray();
586   ImageFileArray vResult = result.getArray();
587   
588   for (unsigned int ix = 0; ix < m_nx; ix++) {
589     ImageFileColumnConst in = vLHS[ix];
590     ImageFileColumn out = vResult[ix];
591     for (unsigned int iy = 0; iy < m_ny; iy++)
592       *out++ = - *in++;
593   }
594   
595   return true;
596 }
597
598 bool
599 ImageFile::sqrt (ImageFile& result) const
600 {
601   if (m_nx != result.nx() || m_ny != result.ny()) {
602     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
603     return false;
604   }
605   
606   if (isComplex() && ! result.isComplex())
607     result.convertRealToComplex();
608   
609   bool bComplexOutput = result.isComplex();
610   ImageFileArrayConst vLHS = getArray();
611   if (! bComplexOutput)   // check if should convert to complex output
612     for (unsigned int ix = 0; ix < m_nx; ix++)
613       for (unsigned int iy = 0; iy < m_ny; iy++)
614         if (! bComplexOutput && vLHS[ix][iy] < 0) {
615           result.convertRealToComplex();
616           bComplexOutput = true;
617           break;
618         }
619         
620         ImageFileArrayConst vLHSImag = getImaginaryArray();
621         ImageFileArray vResult = result.getArray();
622         ImageFileArray vResultImag = result.getImaginaryArray();
623         
624         for (unsigned int ix = 0; ix < m_nx; ix++) {
625           for (unsigned int iy = 0; iy < m_ny; iy++) {
626             if (result.isComplex()) {
627               double dImag = 0;
628               if (isComplex())
629                 dImag = vLHSImag[ix][iy];
630               std::complex<double> cLHS (vLHS[ix][iy], dImag);
631               std::complex<double> cResult = std::sqrt(cLHS);
632               vResult[ix][iy] = cResult.real();
633               vResultImag[ix][iy] = cResult.imag();
634             } else
635               vResult[ix][iy] = ::sqrt (vLHS[ix][iy]);
636           }
637         }
638         
639         
640         return true;
641 }
642
643 bool
644 ImageFile::log (ImageFile& result) const
645 {
646   if (m_nx != result.nx() || m_ny != result.ny()) {
647     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::log]");
648     return false;
649   }
650   
651   if (isComplex() && ! result.isComplex())
652     result.convertRealToComplex();
653   
654   ImageFileArrayConst vLHS = getArray();
655   ImageFileArrayConst vLHSImag = getImaginaryArray();
656   ImageFileArray vResult = result.getArray();
657   ImageFileArray vResultImag = result.getImaginaryArray();
658   
659   for (unsigned int ix = 0; ix < m_nx; ix++) {
660     for (unsigned int iy = 0; iy < m_ny; iy++) {
661       if (result.isComplex()) {
662         double dImag = 0;
663         if (isComplex())
664           dImag = vLHSImag[ix][iy];
665         std::complex<double> cLHS (vLHS[ix][iy], dImag);
666         std::complex<double> cResult = std::log (cLHS);
667         vResult[ix][iy] = cResult.real();
668         vResultImag[ix][iy] = cResult.imag();
669       } else {
670         if (vLHS[ix][iy] > 0)
671           vResult[ix][iy] = ::log (vLHS[ix][iy]);
672         else
673           vResult[ix][iy] = 0;
674       }
675     }
676   }
677   
678   
679   return true;
680 }
681
682 bool
683 ImageFile::exp (ImageFile& result) const
684 {
685   if (m_nx != result.nx() || m_ny != result.ny()) {
686     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
687     return false;
688   }
689   
690   if (isComplex() && ! result.isComplex())
691     result.convertRealToComplex();
692   
693   ImageFileArrayConst vLHS = getArray();
694   ImageFileArrayConst vLHSImag = getImaginaryArray();
695   ImageFileArray vResult = result.getArray();
696   ImageFileArray vResultImag = result.getImaginaryArray();
697   
698   for (unsigned int ix = 0; ix < m_nx; ix++) {
699     for (unsigned int iy = 0; iy < m_ny; iy++) {
700       if (result.isComplex()) {
701         double dImag = 0;
702         if (isComplex())
703           dImag = vLHSImag[ix][iy];
704         std::complex<double> cLHS (vLHS[ix][iy], dImag);
705         std::complex<double> cResult = std::exp (cLHS);
706         vResult[ix][iy] = cResult.real();
707         vResultImag[ix][iy] = cResult.imag();
708       } else
709         vResult[ix][iy] = ::exp (vLHS[ix][iy]);
710     }
711   }
712   
713   
714   return true;
715 }
716
717 bool
718 ImageFile::scaleImage (ImageFile& result) const
719 {
720   unsigned int nx = m_nx;
721   unsigned int ny = m_ny;
722   unsigned int newNX = result.nx();
723   unsigned int newNY = result.ny();
724   
725   double dXScale = static_cast<double>(newNX) / static_cast<double>(nx);
726   double dYScale = static_cast<double>(newNY) / static_cast<double>(ny);
727   
728   if (isComplex() && ! result.isComplex())
729     result.convertRealToComplex();
730   
731   ImageFileArrayConst vReal = getArray();
732   ImageFileArrayConst vImag = getImaginaryArray();
733   ImageFileArray vResult = result.getArray();
734   ImageFileArray vResultImag = result.getImaginaryArray();
735   
736   for (unsigned int ix = 0; ix < newNX; ix++) {
737     for (unsigned int iy = 0; iy < newNY; iy++) {
738       double dXPos = ix / dXScale;
739       double dYPos = iy / dYScale;
740       unsigned int scaleNX = static_cast<unsigned int> (dXPos);
741       unsigned int scaleNY = static_cast<unsigned int> (dYPos);
742       double dXFrac = dXPos - scaleNX;
743       double dYFrac = dYPos - scaleNY;
744       if (scaleNX >= nx - 1 || scaleNY >= ny - 1) {
745         vResult[ix][iy] = vReal[scaleNX][scaleNY];
746         if (result.isComplex()) {
747           if (isComplex())
748             vResultImag[ix][iy] = vImag[scaleNX][scaleNY];
749           else
750             vResultImag[ix][iy] = 0;
751         }
752       } else {
753         vResult[ix][iy] = (1 - dXFrac) * (1 - dYFrac) * vReal[scaleNX][scaleNY] + 
754           dXFrac * (1 - dYFrac) * vReal[scaleNX+1][scaleNY] + 
755           dYFrac * (1 - dXFrac) * vReal[scaleNX][scaleNY+1] +
756           dXFrac * dYFrac * vReal[scaleNX+1][scaleNY+1];
757         if (result.isComplex()) {
758           if (isComplex())
759             vResultImag[ix][iy] = (1 - dXFrac) * (1 - dYFrac) * vImag[scaleNX][scaleNY] + 
760             dXFrac * (1 - dYFrac) * vImag[scaleNX+1][scaleNY] + 
761             dYFrac * (1 - dXFrac) * vImag[scaleNX][scaleNY+1] +
762             dXFrac * dYFrac * vImag[scaleNX+1][scaleNY+1];
763           else
764             vResultImag[ix][iy] = 0;
765         }
766       }
767     }
768   }
769   
770   return true;
771 }
772
773 #ifdef HAVE_FFTW
774 bool
775 ImageFile::fft (ImageFile& result) const
776 {
777   if (m_nx != result.nx() || m_ny != result.ny()) {
778     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
779     return false;
780   }
781   
782   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
783     if (! result.convertRealToComplex ())
784       return false;
785   }
786   
787   fftw_complex* in = new fftw_complex [m_nx * m_ny];
788   
789   ImageFileArrayConst vReal = getArray();
790   ImageFileArrayConst vImag = getImaginaryArray();
791   
792   unsigned int ix, iy;
793   unsigned int iArray = 0;
794   for (ix = 0; ix < m_nx; ix++)
795     for (iy = 0; iy < m_ny; iy++) {
796       in[iArray].re = vReal[ix][iy];
797       if (isComplex())
798         in[iArray].im = vImag[ix][iy];
799       else
800         in[iArray].im = 0;
801       iArray++;
802     }
803     
804     fftwnd_plan plan = fftw2d_create_plan (m_nx, m_ny, FFTW_FORWARD, FFTW_IN_PLACE);
805     
806     fftwnd_one (plan, in, NULL);
807     
808     ImageFileArray vRealResult = result.getArray();
809     ImageFileArray vImagResult = result.getImaginaryArray();
810     iArray = 0;
811     unsigned int iScale = m_nx * m_ny;
812     for (ix = 0; ix < m_nx; ix++)
813       for (iy = 0; iy < m_ny; iy++) {
814         vRealResult[ix][iy] = in[iArray].re / iScale;
815         vImagResult[ix][iy] = in[iArray].im / iScale;
816         iArray++;
817       }
818       
819       fftwnd_destroy_plan (plan);
820       delete in;
821       
822       
823       Fourier::shuffleFourierToNaturalOrder (result);
824       
825       return true;
826 }
827
828
829 bool
830 ImageFile::ifft (ImageFile& result) const
831 {
832   if (m_nx != result.nx() || m_ny != result.ny()) {
833     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
834     return false;
835   }
836   
837   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
838     if (! result.convertRealToComplex ())
839       return false;
840   }
841   
842   ImageFileArrayConst vReal = getArray();
843   ImageFileArrayConst vImag = getImaginaryArray();
844   ImageFileArray vRealResult = result.getArray();
845   ImageFileArray vImagResult = result.getImaginaryArray();
846   unsigned int ix, iy;
847   for (ix = 0; ix < m_nx; ix++)
848     for (iy = 0; iy < m_ny; iy++) {
849       vRealResult[ix][iy] = vReal[ix][iy];
850       if (isComplex()) 
851         vImagResult[ix][iy] = vImag[ix][iy];
852       else
853         vImagResult[ix][iy] = 0;
854     }
855     
856     Fourier::shuffleNaturalToFourierOrder (result);
857     
858     fftw_complex* in = new fftw_complex [m_nx * m_ny];
859     
860     unsigned int iArray = 0;
861     for (ix = 0; ix < m_nx; ix++)
862       for (iy = 0; iy < m_ny; iy++) {
863         in[iArray].re = vRealResult[ix][iy];
864         in[iArray].im = vImagResult[ix][iy];
865         iArray++;
866       }
867       
868       fftwnd_plan plan = fftw2d_create_plan (m_nx, m_ny, FFTW_BACKWARD, FFTW_IN_PLACE);
869       
870       fftwnd_one (plan, in, NULL);
871       
872       iArray = 0;
873       for (ix = 0; ix < m_nx; ix++)
874         for (iy = 0; iy < m_ny; iy++) {
875           vRealResult[ix][iy] = in[iArray].re;
876           vImagResult[ix][iy] = in[iArray].im;
877           iArray++;
878         }
879         
880         fftwnd_destroy_plan (plan);
881         
882         delete in;
883         
884         return true;
885 }
886
887 bool
888 ImageFile::fftRows (ImageFile& result) const
889 {
890   if (m_nx != result.nx() || m_ny != result.ny()) {
891     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
892     return false;
893   }
894   
895   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
896     if (! result.convertRealToComplex ())
897       return false;
898   }
899   
900   fftw_complex* in = new fftw_complex [m_nx];
901   
902   ImageFileArrayConst vReal = getArray();
903   ImageFileArrayConst vImag = getImaginaryArray();
904   
905   fftw_plan plan = fftw_create_plan (m_nx, FFTW_FORWARD, FFTW_IN_PLACE);
906   std::complex<double>* pcRow = new std::complex<double> [m_nx];
907   
908   unsigned int ix, iy;
909   unsigned int iArray = 0;
910   for (iy = 0; iy < m_ny; iy++) {
911     for (ix = 0; ix < m_nx; ix++) {
912       in[ix].re = vReal[ix][iy];
913       if (isComplex())
914         in[ix].im = vImag[ix][iy];
915       else
916         in[ix].im = 0;
917     }
918     
919     fftw_one (plan, in, NULL);
920     
921     for (ix = 0; ix < m_nx; ix++)
922       pcRow[ix] = std::complex<double>(in[ix].re, in[ix].im);
923     
924     Fourier::shuffleFourierToNaturalOrder (pcRow, m_nx);
925     for (ix = 0; ix < m_nx; ix++) {
926       vReal[ix][iy] = pcRow[ix].real();
927       vImag[ix][iy] = pcRow[ix].imag();
928     }
929   }
930   delete [] pcRow;
931   
932   fftw_destroy_plan (plan);
933   delete in;
934   
935   return true;
936 }     
937
938 bool
939 ImageFile::ifftRows (ImageFile& result) const
940 {
941   if (m_nx != result.nx() || m_ny != result.ny()) {
942     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
943     return false;
944   }
945   
946   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
947     if (! result.convertRealToComplex ())
948       return false;
949   }
950   
951   fftw_complex* in = new fftw_complex [m_nx];
952   
953   ImageFileArrayConst vReal = getArray();
954   ImageFileArrayConst vImag = getImaginaryArray();
955   
956   fftw_plan plan = fftw_create_plan (m_nx, FFTW_BACKWARD, FFTW_IN_PLACE);
957   std::complex<double>* pcRow = new std::complex<double> [m_nx];
958   
959   unsigned int ix, iy;
960   unsigned int iArray = 0;
961   for (iy = 0; iy < m_ny; iy++) {
962     for (ix = 0; ix < m_nx; ix++) {
963       double dImag = 0;
964       if (isComplex())
965         dImag = vImag[ix][iy];
966       pcRow[ix] = std::complex<double> (vReal[ix][iy], dImag);
967     }
968     
969     Fourier::shuffleNaturalToFourierOrder (pcRow, m_nx);
970     
971     for (ix = 0; ix < m_nx; ix++) {
972       in[ix].re = pcRow[ix].real();
973       in[ix].im = pcRow[ix].imag();
974     }
975     
976     fftw_one (plan, in, NULL);
977     
978     for (ix = 0; ix < m_nx; ix++) {
979       vReal[ix][iy] = in[ix].re;
980       vImag[ix][iy] = in[ix].im;
981     }
982   }
983   delete [] pcRow;
984   
985   fftw_destroy_plan (plan);
986   delete in;
987   
988   return true;
989 }
990
991 bool
992 ImageFile::fftCols (ImageFile& result) const
993 {
994   return false;
995 }
996
997 bool
998 ImageFile::ifftCols (ImageFile& result) const
999 {
1000   return false;
1001 }
1002
1003 #endif // HAVE_FFTW
1004
1005
1006
1007 bool
1008 ImageFile::fourier (ImageFile& result) const
1009 {
1010   if (m_nx != result.nx() || m_ny != result.ny()) {
1011     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1012     return false;
1013   }
1014   
1015   if (! result.isComplex())
1016     if (! result.convertRealToComplex ())
1017       return false;
1018     
1019     ImageFileArrayConst vLHS = getArray();
1020     ImageFileArrayConst vLHSImag = getImaginaryArray();
1021     ImageFileArray vRealResult = result.getArray();
1022     ImageFileArray vImagResult = result.getImaginaryArray();
1023     
1024     unsigned int ix, iy;
1025     
1026     // alloc output matrix
1027     CTSimComplex** complexOut = new CTSimComplex* [m_nx];
1028     for (ix = 0; ix < m_nx; ix++)
1029       complexOut[ix] = new CTSimComplex [m_ny];
1030     
1031     // fourier each x column
1032     CTSimComplex* pY = new CTSimComplex [m_ny];
1033     for (ix = 0; ix < m_nx; ix++) {
1034       for (iy = 0; iy < m_ny; iy++) {
1035         double dImag = 0;
1036         if (isComplex())
1037           dImag = vLHSImag[ix][iy];
1038         pY[iy] = std::complex<double>(vLHS[ix][iy], dImag);
1039       } 
1040       ProcessSignal::finiteFourierTransform (pY, complexOut[ix], m_ny,  ProcessSignal::FORWARD);
1041     }
1042     delete [] pY;
1043     
1044     // fourier each y row
1045     CTSimComplex* pX = new CTSimComplex [m_nx];
1046     CTSimComplex* complexOutRow = new CTSimComplex [m_nx];
1047     for (iy = 0; iy < m_ny; iy++) {
1048       for (ix = 0; ix < m_nx; ix++)
1049         pX[ix] = complexOut[ix][iy];
1050       ProcessSignal::finiteFourierTransform (pX, complexOutRow, m_nx, ProcessSignal::FORWARD);
1051       for (ix = 0; ix < m_nx; ix++)
1052         complexOut[ix][iy] = complexOutRow[ix];
1053     }
1054     delete [] pX;
1055     delete [] complexOutRow;
1056     
1057     for (ix = 0; ix < m_nx; ix++)
1058       for (iy = 0; iy < m_ny; iy++) {
1059         vRealResult[ix][iy] = complexOut[ix][iy].real();
1060         vImagResult[ix][iy] = complexOut[ix][iy].imag();
1061       }
1062       
1063       Fourier::shuffleFourierToNaturalOrder (result);
1064       
1065       // delete complexOut matrix
1066       for (ix = 0; ix < m_nx; ix++)
1067         delete [] complexOut[ix];
1068       delete [] complexOut;
1069       
1070       return true;
1071 }
1072
1073 bool
1074 ImageFile::inverseFourier (ImageFile& result) const
1075 {
1076   if (m_nx != result.nx() || m_ny != result.ny()) {
1077     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1078     return false;
1079   }
1080   
1081   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
1082     if (! result.convertRealToComplex ())
1083       return false;
1084   }
1085   
1086   ImageFileArrayConst vLHSReal = getArray();
1087   ImageFileArrayConst vLHSImag = getImaginaryArray();
1088   ImageFileArray vRealResult = result.getArray();
1089   ImageFileArray vImagResult = result.getImaginaryArray();
1090   
1091   unsigned int ix, iy;
1092   // alloc 2d complex output matrix
1093   CTSimComplex** complexOut = new CTSimComplex* [m_nx];
1094   for (ix = 0; ix < m_nx; ix++)
1095     complexOut[ix] = new CTSimComplex [m_ny];
1096   
1097   // put input image into result
1098   for (ix = 0; ix < m_nx; ix++)
1099     for (iy = 0; iy < m_ny; iy++) {
1100       vRealResult[ix][iy] = vLHSReal[ix][iy];
1101       if (isComplex())
1102         vImagResult[ix][iy] = vLHSImag[ix][iy];
1103       else
1104         vImagResult[ix][iy] = 0;
1105     }
1106     
1107     Fourier::shuffleNaturalToFourierOrder (result);
1108     
1109     // ifourier each x column
1110     CTSimComplex* pCol = new CTSimComplex [m_ny];
1111     for (ix = 0; ix < m_nx; ix++) {
1112       for (iy = 0; iy < m_ny; iy++) {
1113         pCol[iy] = std::complex<double> (vRealResult[ix][iy], vImagResult[ix][iy]);
1114       }
1115       ProcessSignal::finiteFourierTransform (pCol, complexOut[ix], m_ny,  ProcessSignal::BACKWARD);
1116     }
1117     delete [] pCol;
1118     
1119     // ifourier each y row
1120     CTSimComplex* complexInRow = new CTSimComplex [m_nx];
1121     CTSimComplex* complexOutRow = new CTSimComplex [m_nx];
1122     for (iy = 0; iy < m_ny; iy++) {
1123       for (ix = 0; ix < m_nx; ix++)
1124         complexInRow[ix] = complexOut[ix][iy];
1125       ProcessSignal::finiteFourierTransform (complexInRow, complexOutRow, m_nx, ProcessSignal::BACKWARD);
1126       for (ix = 0; ix < m_nx; ix++)
1127         complexOut[ix][iy] = complexOutRow[ix];
1128     }
1129     delete [] complexInRow;
1130     delete [] complexOutRow;
1131     
1132     for (ix = 0; ix < m_nx; ix++)
1133       for (iy = 0; iy < m_ny; iy++) {
1134         vRealResult[ix][iy] = complexOut[ix][iy].real();
1135         vImagResult[ix][iy] = complexOut[ix][iy].imag();
1136       }
1137       
1138       // delete complexOut matrix
1139       for (ix = 0; ix < m_nx; ix++)
1140         delete [] complexOut[ix];
1141       delete [] complexOut;
1142       
1143       return true;
1144 }
1145
1146
1147 bool
1148 ImageFile::magnitude (ImageFile& result) const
1149 {
1150   if (m_nx != result.nx() || m_ny != result.ny()) {
1151     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1152     return false;
1153   }
1154   
1155   ImageFileArray vReal = getArray();
1156   ImageFileArray vImag = getImaginaryArray();
1157   ImageFileArray vRealResult = result.getArray();
1158   
1159   for (unsigned int ix = 0; ix < m_nx; ix++)
1160     for (unsigned int iy = 0; iy < m_ny; iy++) {
1161       if (isComplex()) 
1162         vRealResult[ix][iy] = ::sqrt (vReal[ix][iy] * vReal[ix][iy] + vImag[ix][iy] * vImag[ix][iy]);
1163       else
1164         vRealResult[ix][iy] = vReal[ix][iy];
1165     }
1166     
1167     if (result.isComplex())
1168       result.convertComplexToReal();
1169     
1170     return true;
1171 }
1172
1173 bool
1174 ImageFile::phase (ImageFile& result) const
1175 {
1176   if (m_nx != result.nx() || m_ny != result.ny()) {
1177     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1178     return false;
1179   }
1180   
1181   ImageFileArray vReal = getArray();
1182   ImageFileArray vImag = getImaginaryArray();
1183   ImageFileArray vRealResult = result.getArray();
1184   
1185   for (unsigned int ix = 0; ix < m_nx; ix++)
1186     for (unsigned int iy = 0; iy < m_ny; iy++) {
1187       if (isComplex())
1188         vRealResult[ix][iy] = ::atan2 (vImag[ix][iy], vReal[ix][iy]);
1189       else
1190         vRealResult[ix][iy] = 0;
1191     }
1192     
1193     if (result.isComplex())
1194       result.convertComplexToReal();
1195     
1196     return true;
1197 }
1198
1199 bool
1200 ImageFile::square (ImageFile& result) const
1201 {
1202   if (m_nx != result.nx() || m_ny != result.ny()) {
1203     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1204     return false;
1205   }
1206   
1207   if (isComplex() && ! result.isComplex())
1208     result.convertRealToComplex();
1209   
1210   ImageFileArrayConst vLHS = getArray();
1211   ImageFileArrayConst vLHSImag = getImaginaryArray();
1212   ImageFileArray vResult = result.getArray();
1213   ImageFileArray vResultImag = result.getImaginaryArray();
1214   
1215   for (unsigned int ix = 0; ix < m_nx; ix++) {
1216     for (unsigned int iy = 0; iy < m_ny; iy++) {
1217       if (result.isComplex()) {
1218         double dImag = 0;
1219         if (isComplex())
1220           dImag = vLHSImag[ix][iy];
1221         std::complex<double> cLHS (vLHS[ix][iy], dImag);
1222         std::complex<double> cResult = cLHS * cLHS;
1223         vResult[ix][iy] = cResult.real();
1224         vResultImag[ix][iy] = cResult.imag();
1225       } else
1226         vResult[ix][iy] = vLHS[ix][iy] * vLHS[ix][iy];
1227     }
1228   }
1229   
1230   
1231   return true;
1232 }
1233
1234 int
1235 ImageFile::convertExportFormatNameToID (const char* const formatName)
1236 {
1237   int formatID = EXPORT_FORMAT_INVALID;
1238   
1239   for (int i = 0; i < s_iExportFormatCount; i++)
1240     if (strcasecmp (formatName, s_aszExportFormatName[i]) == 0) {
1241       formatID = i;
1242       break;
1243     }
1244     
1245     return (formatID);
1246 }
1247
1248 const char*
1249 ImageFile::convertExportFormatIDToName (int formatID)
1250 {
1251   static const char *formatName = "";
1252   
1253   if (formatID >= 0 && formatID < s_iExportFormatCount)
1254     return (s_aszExportFormatName[formatID]);
1255   
1256   return (formatName);
1257 }
1258
1259 const char*
1260 ImageFile::convertExportFormatIDToTitle (const int formatID)
1261 {
1262   static const char *formatTitle = "";
1263   
1264   if (formatID >= 0 && formatID < s_iExportFormatCount)
1265     return (s_aszExportFormatTitle[formatID]);
1266   
1267   return (formatTitle);
1268 }
1269
1270 int
1271 ImageFile::convertImportFormatNameToID (const char* const formatName)
1272 {
1273   int formatID = IMPORT_FORMAT_INVALID;
1274   
1275   for (int i = 0; i < s_iImportFormatCount; i++)
1276     if (strcasecmp (formatName, s_aszImportFormatName[i]) == 0) {
1277       formatID = i;
1278       break;
1279     }
1280     
1281     return (formatID);
1282 }
1283
1284 const char*
1285 ImageFile::convertImportFormatIDToName (int formatID)
1286 {
1287   static const char *formatName = "";
1288   
1289   if (formatID >= 0 && formatID < s_iImportFormatCount)
1290     return (s_aszImportFormatName[formatID]);
1291   
1292   return (formatName);
1293 }
1294
1295 const char*
1296 ImageFile::convertImportFormatIDToTitle (const int formatID)
1297 {
1298   static const char *formatTitle = "";
1299   
1300   if (formatID >= 0 && formatID < s_iImportFormatCount)
1301     return (s_aszImportFormatTitle[formatID]);
1302   
1303   return (formatTitle);
1304 }
1305
1306 bool
1307 ImageFile::importImage (const char* const pszFormat, const char* const pszFilename)
1308 {
1309   int iFormatID = convertImportFormatNameToID (pszFormat);
1310   
1311   if (iFormatID == IMPORT_FORMAT_PPM)
1312     return readImagePPM (pszFilename);
1313 #ifdef HAVE_PNG
1314   else if (iFormatID == IMPORT_FORMAT_PNG)
1315     return readImagePNG (pszFilename);
1316 #endif
1317   
1318   sys_error (ERR_SEVERE, "Invalid format %s [ImageFile::importImage]", pszFormat);
1319   return false;
1320 }
1321
1322 void
1323 ImageFile::skipSpacePPM (FILE* fp)
1324 {
1325   int c = fgetc (fp);
1326   while (isspace (c) || c == '#') {
1327     if (c == '#') {   // comment until end of line
1328       c = fgetc(fp);
1329       while (c != 13 && c != 10)
1330         c = fgetc(fp);
1331     }
1332     else
1333       c = fgetc(fp);
1334   }
1335   
1336   ungetc (c, fp);
1337 }
1338
1339 bool
1340 ImageFile::readImagePPM (const char* const pszFile)
1341 {
1342   FILE* fp = fopen (pszFile, "r");
1343   if ((fp = fopen (pszFile, "r")) == NULL)
1344     return false;
1345   char cSignature = toupper(fgetc(fp));
1346   if (cSignature != 'P') {
1347     fclose(fp);
1348     return false;
1349   }
1350   cSignature = fgetc(fp);
1351   if (cSignature == '5' || cSignature == '6') { // binary modes
1352     fclose(fp);
1353     fp = fopen(pszFile, "rb"); // reopen in binary mode
1354     fgetc(fp);
1355     fgetc(fp);
1356   } else if (cSignature != '2' && cSignature != '3') {
1357     fclose(fp);
1358     return false;
1359   }
1360   
1361   int nRows, nCols, iMaxValue;
1362   skipSpacePPM (fp); 
1363   if (fscanf (fp, "%d", &nCols) != 1) {
1364     fclose(fp);
1365     return false;
1366   }
1367   skipSpacePPM (fp);
1368   if (fscanf (fp, "%d", &nRows) != 1) {
1369     fclose(fp);
1370     return false;
1371   }
1372   skipSpacePPM (fp);
1373   if (fscanf (fp, "%d", &iMaxValue) != 1) {
1374     fclose(fp);
1375     return false;
1376   }
1377   setArraySize (nRows, nCols);
1378   
1379   if (cSignature == '5' || cSignature == '6') { // binary modes
1380     int c = fgetc(fp);
1381     if (c == 13) {
1382       c = fgetc(fp);
1383       if (c != 10)  // read msdos 13-10 newline
1384         ungetc(c, fp);
1385     }
1386   } else
1387     skipSpacePPM (fp); // ascii may have comments
1388   
1389   double dMaxValue = iMaxValue;
1390   ImageFileArray v = getArray();
1391   for (int iy = nRows - 1; iy >= 0; iy--) {
1392     for (int ix = 0; ix < nCols; ix++) {
1393       int iGS, iR, iG, iB;
1394       double dR, dG, dB;
1395       switch (cSignature) {
1396       case '2':
1397         if (fscanf(fp, "%d ", &iGS) != 1) {
1398           fclose(fp);
1399           return false;
1400         }
1401         v[ix][iy] = iGS / dMaxValue;
1402         break;
1403       case '5':
1404         iGS = fgetc(fp);
1405         if (iGS == EOF) {
1406           fclose(fp);
1407           return false;
1408         }
1409         v[ix][iy] = iGS / dMaxValue;
1410         break;
1411       case '3':
1412         if (fscanf (fp, "%d %d %d ", &iR, &iG, &iB) != 3) {
1413           fclose(fp);
1414           return false;
1415         }
1416         dR = iR / dMaxValue;
1417         dG = iG / dMaxValue;
1418         dB = iB / dMaxValue;
1419         v[ix][iy] = colorToGrayscale (dR, dG, dB);
1420         break;
1421       case '6':
1422         iR = fgetc(fp);
1423         iG = fgetc(fp);
1424         iB = fgetc(fp);
1425         if (iB == EOF) {
1426           fclose(fp);
1427           return false;
1428         }
1429         dR = iR / dMaxValue;
1430         dG = iG / dMaxValue;
1431         dB = iB / dMaxValue;
1432         v[ix][iy] = colorToGrayscale (dR, dG, dB);
1433         break;
1434       }
1435     }
1436   }
1437   
1438   fclose(fp);
1439   return true;
1440 }
1441
1442 #ifdef HAVE_PNG
1443 bool
1444 ImageFile::readImagePNG (const char* const pszFile)
1445 {
1446   FILE* fp = fopen(pszFile, "rb");
1447   if (!fp) 
1448     return false;
1449   unsigned char header[8];
1450   fread (header, 1, 8, fp);
1451   if (png_sig_cmp (header, 0, 8)) {
1452     fclose (fp);
1453     return false;
1454   }
1455   
1456   png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1457   if (!png_ptr) {
1458     fclose(fp);
1459     return false;
1460   }
1461   
1462   png_infop info_ptr = png_create_info_struct(png_ptr);
1463   if (!info_ptr) {
1464     png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
1465     fclose(fp);
1466     return false;
1467   }
1468   
1469   png_infop end_info = png_create_info_struct(png_ptr);
1470   if (!end_info) {
1471     png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
1472     fclose(fp);
1473     return false;
1474   }
1475   
1476   if (setjmp(png_ptr->jmpbuf)) {
1477     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1478     fclose(fp);
1479     return false;
1480   }
1481   
1482   png_init_io(png_ptr, fp);
1483   png_set_sig_bytes(png_ptr, 8);
1484   png_read_info(png_ptr, info_ptr);
1485   
1486   int width = png_get_image_width (png_ptr, info_ptr);
1487   int height = png_get_image_height (png_ptr, info_ptr);
1488   int bit_depth = png_get_bit_depth (png_ptr, info_ptr);
1489   int color_type = png_get_color_type (png_ptr, info_ptr);
1490   
1491   if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) 
1492     png_set_expand(png_ptr);
1493   
1494   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) 
1495     png_set_expand(png_ptr);
1496   
1497   if (bit_depth < 8)
1498     png_set_packing(png_ptr);
1499   
1500   if (color_type & PNG_COLOR_MASK_ALPHA)
1501     png_set_strip_alpha(png_ptr);
1502   
1503   if (bit_depth == 16)
1504     png_set_swap(png_ptr); // convert to little-endian format
1505   
1506   png_read_update_info(png_ptr, info_ptr); // update with transformations
1507   int rowbytes = png_get_rowbytes (png_ptr, info_ptr);
1508   bit_depth = png_get_bit_depth (png_ptr, info_ptr);
1509   color_type = png_get_color_type (png_ptr, info_ptr);
1510   
1511   png_bytep* row_pointers = new png_bytep [height];
1512   int i;
1513   for (i = 0; i < height; i++)
1514     row_pointers[i] = new unsigned char [rowbytes];
1515   
1516   png_read_image(png_ptr, row_pointers);
1517   
1518   setArraySize (width, height);
1519   ImageFileArray v = getArray();
1520   for (int iy = 0; iy < height; iy++) {
1521     for (int ix = 0; ix < width; ix++) {
1522       double dV;
1523       if (color_type == PNG_COLOR_TYPE_GRAY) {
1524         if (bit_depth == 8)
1525           dV = row_pointers[iy][ix] / 255.;
1526         else if (bit_depth == 16) {
1527           int iBase = ix * 2;
1528           dV = (row_pointers[iy][iBase] + (row_pointers[iy][iBase+1] << 8)) / 65536.;
1529         }
1530       } else if (color_type == PNG_COLOR_TYPE_RGB) {
1531         if (bit_depth == 8) {
1532           int iBase = ix * 3;
1533           double dR = row_pointers[iy][iBase] / 255.;
1534           double dG = row_pointers[iy][iBase+1] / 255.;
1535           double dB = row_pointers[iy][iBase+2] / 255.;
1536           dV = colorToGrayscale (dR, dG, dR);
1537         }
1538       }
1539       v[ix][height-iy-1] = dV;
1540     }
1541   }
1542   
1543   png_read_end(png_ptr, end_info);
1544   png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1545   
1546   for (i = 0; i < height; i++)
1547     delete row_pointers[i];
1548   delete row_pointers;
1549   
1550   fclose (fp);
1551   return true;
1552 }
1553 #endif
1554
1555 bool
1556 ImageFile::exportImage (const char* const pszFormat, const char* const pszFilename, int nxcell, int nycell, double densmin, double densmax)
1557 {
1558   int iFormatID = convertExportFormatNameToID (pszFormat);
1559   
1560   if (iFormatID == EXPORT_FORMAT_PGM)
1561     return writeImagePGM (pszFilename, nxcell, nycell, densmin, densmax);
1562   else if (iFormatID == EXPORT_FORMAT_PGMASCII)
1563     return writeImagePGMASCII (pszFilename, nxcell, nycell, densmin, densmax);
1564   else if (iFormatID == EXPORT_FORMAT_PNG)
1565     return writeImagePNG (pszFilename, 8, nxcell, nycell, densmin, densmax);
1566   else if (iFormatID == EXPORT_FORMAT_PNG16)
1567     return writeImagePNG (pszFilename, 16, nxcell, nycell, densmin, densmax);
1568   
1569   sys_error (ERR_SEVERE, "Invalid format %s [ImageFile::exportImage]", pszFormat);
1570   return false;
1571 }
1572
1573
1574 bool
1575 ImageFile::writeImagePGM (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1576 {
1577   FILE *fp;
1578   int nx = m_nx;
1579   int ny = m_ny;
1580   ImageFileArray v = getArray();
1581   
1582   unsigned char* rowp = new unsigned char [nx * nxcell];
1583   
1584   if ((fp = fopen (outfile, "wb")) == NULL)
1585     return false;
1586   
1587   fprintf(fp, "P5\n");
1588   fprintf(fp, "%d %d\n", nx, ny);
1589   fprintf(fp, "255\n");
1590   
1591   for (int irow = ny - 1; irow >= 0; irow--) {
1592     for (int icol = 0; icol < nx; icol++) {
1593       int pos = icol * nxcell;
1594       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1595       dens = clamp (dens, 0., 1.);
1596       for (int p = pos; p < pos + nxcell; p++) {
1597         rowp[p] = static_cast<unsigned int> (dens * 255.);
1598       }
1599     }
1600     for (int ir = 0; ir < nycell; ir++) {
1601       for (int ic = 0; ic < nx * nxcell; ic++) 
1602         fputc( rowp[ic], fp );
1603     }
1604   }
1605   
1606   delete rowp;
1607   fclose(fp);
1608   
1609   return true;
1610 }
1611
1612 bool
1613 ImageFile::writeImagePGMASCII (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1614 {
1615   FILE *fp;
1616   int nx = m_nx;
1617   int ny = m_ny;
1618   ImageFileArray v = getArray();
1619   
1620   unsigned char* rowp = new unsigned char [nx * nxcell];
1621   
1622   if ((fp = fopen (outfile, "wb")) == NULL)
1623     return false;
1624   
1625   fprintf(fp, "P2\n");
1626   fprintf(fp, "%d %d\n", nx, ny);
1627   fprintf(fp, "255\n");
1628   
1629   for (int irow = ny - 1; irow >= 0; irow--) {
1630     for (int icol = 0; icol < nx; icol++) {
1631       int pos = icol * nxcell;
1632       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1633       dens = clamp (dens, 0., 1.);
1634       for (int p = pos; p < pos + nxcell; p++) {
1635         rowp[p] = static_cast<unsigned int> (dens * 255.);
1636       }
1637     }
1638     for (int ir = 0; ir < nycell; ir++) {
1639       for (int ic = 0; ic < nx * nxcell; ic++) 
1640         fprintf(fp, "%d ", rowp[ic]);
1641       fprintf(fp, "\n");
1642     }
1643   }
1644   
1645   delete rowp;
1646   fclose(fp);
1647   
1648   return true;
1649 }
1650
1651
1652 #ifdef HAVE_PNG
1653 bool
1654 ImageFile::writeImagePNG (const char* const outfile, int bitdepth, int nxcell, int nycell, double densmin, double densmax)
1655 {
1656   double max_out_level = (1 << bitdepth) - 1;
1657   int nx = m_nx;
1658   int ny = m_ny;
1659   ImageFileArray v = getArray();
1660   
1661   unsigned char* rowp = new unsigned char [nx * nxcell * (bitdepth / 8)];
1662   
1663   FILE *fp = fopen (outfile, "wb");
1664   if (! fp)
1665     return false;
1666   
1667   png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1668   if (! png_ptr)
1669     return false;
1670   
1671   png_infop info_ptr = png_create_info_struct (png_ptr);
1672   if (! info_ptr) {
1673     png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
1674     fclose (fp);
1675     return false;
1676   }
1677   
1678   if (setjmp (png_ptr->jmpbuf)) {
1679     png_destroy_write_struct (&png_ptr, &info_ptr);
1680     fclose (fp);
1681     return false;
1682   }
1683   
1684   png_init_io(png_ptr, fp);
1685   
1686   png_set_IHDR (png_ptr, info_ptr, nx * nxcell, ny * nycell, bitdepth, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT);
1687   
1688   png_write_info(png_ptr, info_ptr);
1689   for (int irow = ny - 1; irow >= 0; irow--) {
1690     png_bytep row_pointer = rowp;
1691     
1692     for (int icol = 0; icol < nx; icol++) {
1693       int pos = icol * nxcell;
1694       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1695       dens = clamp (dens, 0., 1.);
1696       unsigned int outval = static_cast<unsigned int> (dens * max_out_level);
1697       
1698       for (int p = pos; p < pos + nxcell; p++) {
1699         if (bitdepth == 8)
1700           rowp[p] = outval;
1701         else {
1702           int rowpos = p * 2;
1703           rowp[rowpos+1] = (outval >> 8) & 0xFF;
1704           rowp[rowpos] = (outval & 0xFF);
1705         }
1706       }
1707     }
1708     for (int ir = 0; ir < nycell; ir++)
1709       png_write_rows (png_ptr, &row_pointer, 1);
1710   }
1711   
1712   png_write_end (png_ptr, info_ptr);
1713   png_destroy_write_struct (&png_ptr, &info_ptr);
1714   delete rowp;
1715   
1716   fclose(fp);
1717   
1718   return true;
1719 }
1720 #endif
1721
1722 #ifdef HAVE_GD
1723 #include "gd.h"
1724 static const int N_GRAYSCALE=256;
1725
1726 bool
1727 ImageFile::writeImageGIF (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1728 {
1729   int gs_indices[N_GRAYSCALE];
1730   int nx = m_nx;
1731   int ny = m_ny;
1732   ImageFileArray v = getArray();
1733   
1734   unsigned char* rowp = new unsigned char [nx * nxcell];
1735   
1736   gdImagePtr gif = gdImageCreate(nx * nxcell, ny * nycell);
1737   for (int i = 0; i < N_GRAYSCALE; i++)
1738     gs_indices[i] = gdImageColorAllocate(gif, i, i, i);
1739   
1740   int lastrow = ny * nycell - 1;
1741   for (int irow = 0; irow < ny; irow++) {
1742     int rpos = irow * nycell;
1743     for (int ir = rpos; ir < rpos + nycell; ir++) {
1744       for (int icol = 0; icol < nx; icol++) {
1745         int cpos = icol * nxcell;
1746         double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1747         dens = clamp(dens, 0., 1.);
1748         for (int ic = cpos; ic < cpos + nxcell; ic++) {
1749           rowp[ic] = (unsigned int) (dens * (double) (N_GRAYSCALE - 1));
1750           gdImageSetPixel(gif, ic, lastrow - ir, gs_indices[rowp[ic]]);
1751         }
1752       }
1753     }
1754   }
1755   
1756   FILE *out;
1757   if ((out = fopen (outfile,"w")) == NULL) {
1758     sys_error(ERR_SEVERE, "Error opening output file %s for writing", outfile);
1759     return false;
1760   }
1761   gdImageGif(gif,out);
1762   fclose(out);
1763   gdImageDestroy(gif);
1764   
1765   delete rowp;
1766   
1767   return true;
1768 }
1769 #endif
1770