Isis 3.0 Programmer Reference
Back | Home
ProcessImportFits.cpp
Go to the documentation of this file.
1 
23 #include "ProcessImportFits.h"
24 
25 #include <iostream>
26 #include <math.h>
27 
28 #include <QDebug>
29 #include <QString>
30 #include <sstream>
31 
32 #include "IException.h"
33 #include "IString.h"
34 #include "LineManager.h"
35 #include "Preference.h"
36 #include "Pvl.h"
37 #include "PvlGroup.h"
38 #include "PixelType.h"
39 #include "SpecialPixel.h"
40 #include "UserInterface.h"
41 
42 namespace Isis {
43 
48  m_fitsLabels = NULL;
49  m_headerSizes = NULL;
50  m_dataStarts = NULL;
51  }
52 
53 
58  delete m_fitsLabels;
59  delete m_headerSizes;
60  delete m_dataStarts;
61  m_file.close();
62  }
63 
64 
71 
75 
76  // Process each FITS label area. Storing each in its own PvlGroup
77  char readBuf[81];
78  IString line = "";
79  unsigned int place;
80 
81  // The main FITS label starts at the beginning of the file
82  // FITS extension labels start after the previous data and on a 2080 byte boundry
83  // Each FITS keyword in all lables is store in 80 bytes (space padded to 80 if necessary)
84 
85  // Start at the beginning of the file for the main FITS label
86  m_file.seekg(0, std::ios_base::beg);
87 
88  // Read the first label line (80 chars)
89  // We are assuming the file pointer is set to the beginning of the first/next label
90  while (m_file.read(readBuf, 80) && m_file.gcount() == 80) {
91 
92  PvlGroup *fitsLabel = new PvlGroup("FitsLabels");
93 
94  readBuf[80] = '\0';
95  line = readBuf;
96  place = 80;
97 
98  // Process each fits label record (80 bytes) and place keyword, value pairs into PvlKeywords
99  // with any associated comments
100  while (line.substr(0, 3) != "END") {
101 
102  // Check for blank lines
103  if (line.substr(0, 1) != " " && line.substr(0, 1) != "/") {
104  // Name of keyword
105  PvlKeyword label(line.Token(" =").ToQt()); // Stop on spaces OR equal sign
106  // Remove up to beginning of data
107  line.TrimHead(" =");
108  line.TrimTail(" ");
109  if (label.name() == "COMMENT" || label.name() == "HISTORY") {
110  label += line.ToQt();
111  }
112  else {
113  // Check for a quoted value
114  if (line.substr(0,1) == "'") {
115  line.TrimHead("'");
116  label += line.Token("'").TrimHead(" ").TrimTail(" ").ToQt();
117  line.TrimHead(" '");
118  }
119  else {
120  // Access any remaining data without the trailing comment if there is one
121  IString value = line.Token("/");
122  // Clear to end of data
123  value.TrimTail(" ");
124  label += value.ToQt();
125  line.TrimHead(" ");
126  }
127  // If the line still has anything in it, treat it is as a comment.
128  if (line.size() > 0) {
129  line.TrimHead(" /");
130  label.addComment(line.ToQt());
131  // A possible format for units, other possiblites exist.
132  if (line != line.Token("[")) {
133  label.setUnits(line.Token("[").Token("]").ToQt());
134  }
135  }
136  }
137  fitsLabel->addKeyword(label);
138  }
139 
140  // Read the next label line
141  m_file.read(readBuf, 80);
142  readBuf[80] = '\0';
143  line = readBuf;
144  place += 80;
145  }
146 
147  // Save off the PvlGroup and the number of records read from this label
148  m_fitsLabels->push_back(fitsLabel);
149  m_headerSizes->push_back((int)ceil(place / 2880.0));
150 
151  // The file pointer should be pointing at the end of the record that contained "END"
152  // Move the file pointer past the padding after the "END" (i.e., points to start of data)
153  std::streamoff jump;
154  jump = m_headerSizes->last() * 2880 - place;
155  m_file.seekg(jump, std::ios_base::cur);
156 
157  m_dataStarts->push_back(m_file.tellg());
158 
159  // NOTE: For now we only handle image data (i.e., keywords BITPIX & NAXIS & NAXISx must exist)
160  // Does this look like a label for a FITS image? Stop after the first label that does not
161  // because we don't know how to move the file pointer past a non-image data extension.
162  if (fitsLabel->hasKeyword("BITPIX") && fitsLabel->hasKeyword("NAXIS") &&
163  fitsLabel->hasKeyword("NAXIS1")) {
164 
165  int bytesPerPixel = 0;
166  bytesPerPixel = (int)((*fitsLabel)["BITPIX"]);
167  bytesPerPixel = std::abs(bytesPerPixel);
168  bytesPerPixel /= 8;
169 
170  unsigned int axis1 = 1;
171  axis1 = toInt((*fitsLabel)["NAXIS1"]);
172 
173  unsigned int axis2 = 1;
174  if (fitsLabel->hasKeyword("NAXIS2")) {
175  axis2 = toInt((*fitsLabel)["NAXIS2"]);
176  }
177 
178  unsigned int axis3 = 1;
179  if (fitsLabel->hasKeyword("NAXIS3")) {
180  axis3 = toInt((*fitsLabel)["NAXIS3"]);
181  }
182 
183  jump = (int)(ceil(bytesPerPixel * axis1 * axis2 * axis3 / 2880.0) * 2880.0);
184  m_file.seekg(jump, std::ios_base::cur);
185  }
186  // Do we have at least on header that looks like it has image data? If so, we can continue,
187  // but ignore the rest of the file because we don't know how to skip over a non-image data.
188  else if (m_fitsLabels->size() > 1) {
189  m_fitsLabels->pop_back();
190  m_headerSizes->pop_back();
191  m_dataStarts->pop_back();
192  break;
193  }
194  else {
195  QString msg = QObject::tr("The FITS file does not contain a section header that looks "
196  "like it describes an image [%1]").arg(m_name.toString());
198  }
199  }
200  }
201 
202 
209  PvlGroup ProcessImportFits::fitsLabel(int labelNumber) const {
210 
211  if (labelNumber >= m_fitsLabels->size()) {
212  QString msg = QObject::tr("The requested label number [%1], from file [%2] is "
213  "past the last image in this FITS file. Image count is [%3]").arg(labelNumber).
214  arg(m_name.expanded()).arg(m_fitsLabels->size()-1);
216  }
217 
218  if (!m_fitsLabels) {
219  QString msg = QObject::tr("The FITS label has not been initialized, call setFitsFile first");
221  }
222  else if (m_fitsLabels->size() < labelNumber) {
223  QString msg = QObject::tr("The requested FITS label number does not exist from file [%1]").arg(m_name.toString());
225  }
226 
227  return *(*m_fitsLabels)[labelNumber];
228  }
229 
230 
238 
239  // NOTE: This needs to be changed over to use translation files
240 
241  // Attempt to extract the standard instrument group keywords
242  PvlGroup inst("Instrument");
243  if (fitsLabel.hasKeyword("DATE-OBS")) {
244  inst += PvlKeyword("StartTime", fitsLabel["DATE-OBS"][0]);
245  }
246  if (fitsLabel.hasKeyword("OBJECT")) {
247  inst += PvlKeyword("Target", fitsLabel["OBJECT"][0]);
248  }
249  if (fitsLabel.hasKeyword("INSTRUME")) {
250  inst += PvlKeyword("InstrumentId", fitsLabel["INSTRUME"][0]);
251  }
252  if (fitsLabel.hasKeyword("OBSERVER")) {
253  inst += PvlKeyword("SpacecraftName", fitsLabel["OBSERVER"][0]);
254  }
255 
256  return inst;
257  }
258 
259 
266  m_name = fitsFile;
267 
268  SetInputFile(fitsFile.toString()); // Make sure the file exists
269 
270  m_file.open(fitsFile.expanded().toLocal8Bit().constData(), std::ios::in | std::ios::binary);
271 
272  if (!m_file.is_open()) {
273  QString msg = QObject::tr("Unable to open FITS formatted file [%1]").arg(fitsFile.toString());
275  }
276 
277  // Get the FITS labels internalized
279 
280  // Check to make sure it is a FITS file we can handle
281  PvlGroup label = fitsLabel(0);
282  if (label["SIMPLE"][0] == "F") {
283  QString msg = QObject::tr("The file [%1] can not be processed. It is an unsupported format.").
284  arg(fitsFile.toString());
286  }
287 
288  m_file.close();
289  }
290 
291 
302 
303  if (labelNumber >= m_fitsLabels->size()) {
304  QString msg = QObject::tr("The requested label number [%1], from file [%2] is "
305  "past the last image in this FITS file [%3]").arg(labelNumber).
306  arg(InputFile()).arg(m_fitsLabels->size()-1);
308  }
309 
310  PvlGroup label = *(*m_fitsLabels)[labelNumber];
311 
312  // Set the ProcessImport to skip over all the previous images and their labels and the label for
313  // this image. Don't save this info (think memory)
314  SetFileHeaderBytes((*m_dataStarts)[labelNumber]);
315  //SaveFileHeader();
316 
317  // Find pixel type. NOTE: There are several unsupported possiblites
318  Isis::PixelType type;
319  QString msg = "";
320  switch (toInt(label["BITPIX"][0])) {
321  case 8:
322  type = Isis::UnsignedByte;
323  break;
324  case 16:
325  type = Isis::SignedWord;
326  break;
327  case 32:
328  type = Isis::SignedInteger;
329  break;
330  case -32:
331  type = Isis::Real;
332  break;
333  case 64:
334  msg = "Signed 64 bit integer (long) pixel type is not supported at this time";
336  break;
337  case -64:
338  type = Isis::Double;
339  break;
340  default:
341  msg = "Unknown pixel type [" + label["BITPIX"][0] + "] is not supported for imported";
343  break;
344  }
345 
346  SetPixelType(type);
347 
348  // It is possible to have a NAXIS value of 0 meaning no data, the file could include
349  // xtensions with data, however, those aren't supported because we need the code to know
350  // how to skip over them.
351  // NOTE: FITS files, at least the ones seen till now, do not specify a line prefix or suffix
352  // data byte count. Some FITS files do have them and ISIS needs to remove them so it is not
353  // considered part of the DNs. So, use the parent class' prefix/suffix byte count to reduce
354  // the number of samples.
355  if (Organization() == BSQ) {
356  if (toInt(label["NAXIS"][0]) == 2) {
357  SetDimensions(toInt(label["NAXIS1"][0]) - (DataPrefixBytes()+DataSuffixBytes())/SizeOf(type),
358  toInt(label["NAXIS2"][0]), 1);
359  }
360  else if (toInt(label["NAXIS"][0]) == 3) {
361  SetDimensions(toInt(label["NAXIS1"][0]) - (DataPrefixBytes()+DataSuffixBytes())/SizeOf(type),
362  toInt(label["NAXIS2"][0]), toInt(label["NAXIS3"][0]));
363  }
364  else {
365  QString msg = "NAXIS count of [" + label["NAXIS"][0] + "] is not supported at this time";
367  }
368  }
369  else if (Organization() == BIL) {
370  if (toInt(label["NAXIS"][0]) == 2) {
371  SetDimensions(toInt(label["NAXIS1"][0]) - (DataPrefixBytes()+DataSuffixBytes())/SizeOf(type),
372  1, toInt(label["NAXIS2"][0]));
373  }
374  else if (toInt(label["NAXIS"][0]) == 3) {
375  SetDimensions(toInt(label["NAXIS1"][0]) - (DataPrefixBytes()+DataSuffixBytes())/SizeOf(type),
376  toInt(label["NAXIS3"][0]), toInt(label["NAXIS2"][0]));
377  }
378  else {
379  QString msg = "NAXIS count of [" + label["NAXIS"][0] + "] is not supported at this time";
381  }
382  }
383  else if (Organization() == BIP) {
384  QString msg = "BIP (Band interleaved by pixel) organization is not supported at this time.";
386  }
387  else {
388  QString msg = "Unknown organization is not supported.";
390  }
391 
392  // Base and multiplier
393  if (label.hasKeyword("BZERO")) {
394  SetBase(toDouble(label["BZERO"][0]));
395  }
396  else {
397  SetBase(0.0);
398  }
399  if (label.hasKeyword("BSCALE")) {
400  SetMultiplier(toDouble(label["BSCALE"][0]));
401  }
402  else {
403  SetMultiplier(1.0);
404  }
405 
406  // Byte order
407  SetByteOrder(Isis::Msb);
408 
409  }
410 
411 } // end namespace Isis
ProcessImportFits()
Constructor for ProcessImportFits.
QString ToQt() const
Retuns the object string as a QString.
Definition: IString.cpp:884
File name manipulation and expansion.
Definition: FileName.h:111
int SizeOf(Isis::PixelType pixelType)
Returns the number of bytes of the specified PixelType.
Definition: PixelType.h:62
int toInt(const QString &string)
Global function to convert from a string to an integer.
Definition: IString.cpp:108
Interleave Organization() const
Gets the organization of the input cube.
IString TrimHead(const std::string &chars)
Trims The input characters from the beginning of the object IString.
Definition: IString.cpp:573
int DataPrefixBytes() const
This method returns the number of data prefix bytes.
void addKeyword(const PvlKeyword &keyword, const InsertMode mode=Append)
Add a keyword to the container.
void setProcessFileStructure(int labelNumber)
Sets the Process file structure parameters based on the FITS labels of choice.
$Revision: $ $Date:
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:164
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:154
FileName m_name
The name of the input FITS file.
QString InputFile()
Sets the name of the input file to be read in the import StartProcess method and verifies its existan...
void SetDimensions(const int ns, const int nl, const int nb)
Sets the physical size of the input cube.
PixelType
Enumerations for Isis Pixel Types.
Definition: PixelType.h:43
IString Token(const IString &separator)
Returns the first token in the IString.
Definition: IString.cpp:912
QList< int > * m_headerSizes
The number/count of 2880 byte header records for each header section.
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:38
A type of error that could only have occurred due to a mistake on the user&#39;s part (e...
Definition: IException.h:134
A single keyword-value pair.
Definition: PvlKeyword.h:98
void SetPixelType(const Isis::PixelType type)
Sets the pixel type of the input file.
QList< int > * m_dataStarts
The starting byte of the data for each image.
void extractFitsLabels()
Extract all the FITS labels from the file.
Band Sequential Format (i.e.
Band Interleaved By Pixel Format (i.e.
int DataSuffixBytes() const
This method returns the number of data duffix bytes.
void setFitsFile(FileName fitsFile)
Opens a FITS file and reads the FITS labels.
Isis exception class.
Definition: IException.h:99
Adds specific functionality to C++ strings.
Definition: IString.h:179
void SetMultiplier(const double mult)
Sets the core multiplier of the input cube.
virtual ~ProcessImportFits()
Destructor for ProcessImportFits.
PvlGroup standardInstrumentGroup(PvlGroup fitsLabel) const
Return a populated instrument group.
void SetFileHeaderBytes(const int bytes)
This method sets the number of bytes in the header of a file.
void SetBase(const double base)
Sets the core base of the input cube.
void SetInputFile(const QString &file)
Sets the name of the input file to be read in the import StartProcess method and verifies its existan...
QList< PvlGroup * > * m_fitsLabels
Holds the PvlGroups with the converted FITS labels from the main and all extensions.
std::ifstream m_file
The stream used to read the FITS file.
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
PvlGroup fitsLabel(int labelNumber) const
Supplies the requested FITS label.
IString TrimTail(const std::string &chars)
Trims the input characters from the end of the object IString.
Definition: IString.cpp:602
void SetByteOrder(const Isis::ByteOrder order)
Sets the byte order of the input file.
Band Interleaved By Line Format (i.e.

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the ISIS Support Center
File Modified: 07/12/2023 23:26:26