core/vil/file_formats/vil_dicom_header.cxx
Go to the documentation of this file.
00001 // DicomHeaderFormat.cxx
00002 // =====================
00003 //
00004 // The implementation of the vil_dicom_header_format class to read
00005 // and write the header part of a dicom file.
00006 //
00007 // Author: Chris Wolstenholme
00008 // E-mail: cwolstenholme@imorphics.com
00009 // Copyright (c) 2001 iMorphics Ltd
00010 
00011 #include <vil/vil_config.h>
00012 #if HAS_DCMTK
00013 
00014 #include "vil_dicom_header.h"
00015 #include <vil/vil_stream.h>
00016 #include <vcl_iostream.h>
00017 #include <vcl_cstdlib.h>
00018 
00019 //================================================================
00020 
00021 void
00022 vil_dicom_header_info_clear( vil_dicom_header_info& info )
00023 {
00024   // Clear all the elements of the info structure
00025 
00026   // Identity info
00027   info.header_valid_ = false;
00028   info.file_type_ = VIL_DICOM_HEADER_DTUNKNOWN;
00029   info.file_endian_ = VIL_DICOM_HEADER_DEUNKNOWN;
00030   info.sys_endian_ = VIL_DICOM_HEADER_DEUNKNOWN;
00031   info.image_type_ = VIL_DICOM_HEADER_DITUNKNOWN;
00032   info.image_id_type_ = "";
00033   info.sop_cl_uid_ = "";
00034   info.sop_in_uid_ = "";
00035   info.study_date_ = VIL_DICOM_HEADER_UNSPECIFIED;
00036   info.series_date_ = VIL_DICOM_HEADER_UNSPECIFIED;
00037   info.acquisition_date_ = VIL_DICOM_HEADER_UNSPECIFIED;
00038   info.image_date_ = VIL_DICOM_HEADER_UNSPECIFIED;
00039   info.study_time_ = VIL_DICOM_HEADER_UNSPECIFIED;
00040   info.series_time_ = VIL_DICOM_HEADER_UNSPECIFIED;
00041   info.acquisition_time_ = VIL_DICOM_HEADER_UNSPECIFIED;
00042   info.image_time_ = VIL_DICOM_HEADER_UNSPECIFIED;
00043   info.accession_number_ = "";
00044   info.modality_ = "";
00045   info.manufacturer_ = "";
00046   info.institution_name_ = "";
00047   info.institution_addr_ = "";
00048   info.ref_phys_name_ = "";
00049   info.station_name_ = "";
00050   info.study_desc_ = "";
00051   info.att_phys_name_ = "";
00052   info.operator_name_ = "";
00053   info.model_name_ = "";
00054 
00055   // Patient info
00056   info.patient_name_ = "";
00057   info.patient_id_ = "";
00058   info.patient_dob_ = VIL_DICOM_HEADER_UNSPECIFIED;
00059   info.patient_sex_ = "";
00060   info.patient_age_ = "";
00061   info.patient_weight_ = VIL_DICOM_HEADER_UNSPECIFIED;
00062   info.patient_hist_ = "";
00063 
00064   // Acquisition info
00065   info.scanning_seq_ = "";
00066   info.sequence_var_ = "";
00067   info.scan_options_ = "";
00068   info.mr_acq_type_ = "";
00069   info.sequence_name_ = "";
00070   info.angio_flag_ = "";
00071   info.slice_thickness_ = VIL_DICOM_HEADER_UNSPECIFIED;
00072   info.repetition_time_ = VIL_DICOM_HEADER_UNSPECIFIED;
00073   info.echo_time_ = VIL_DICOM_HEADER_UNSPECIFIED;
00074   info.inversion_time_ = VIL_DICOM_HEADER_UNSPECIFIED;
00075   info.number_of_averages_ = VIL_DICOM_HEADER_UNSPECIFIED;
00076   info.echo_numbers_ = VIL_DICOM_HEADER_UNSPECIFIED;
00077   info.mag_field_strength_ = VIL_DICOM_HEADER_UNSPECIFIED;
00078   info.echo_train_length_ = VIL_DICOM_HEADER_UNSPECIFIED;
00079   info.pixel_bandwidth_ = VIL_DICOM_HEADER_UNSPECIFIED;
00080   info.software_vers_ = "";
00081   info.protocol_name_ = "";
00082   info.heart_rate_ = VIL_DICOM_HEADER_UNSPECIFIED;
00083   info.card_num_images_ = VIL_DICOM_HEADER_UNSPECIFIED;
00084   info.trigger_window_ = VIL_DICOM_HEADER_UNSPECIFIED;
00085   info.reconst_diameter_ = VIL_DICOM_HEADER_UNSPECIFIED;
00086   info.receiving_coil_ = "";
00087   info.phase_enc_dir_ = "";
00088   info.flip_angle_ = VIL_DICOM_HEADER_UNSPECIFIED;
00089   info.sar_ = VIL_DICOM_HEADER_UNSPECIFIED;
00090   info.patient_pos_ = "";
00091 
00092   // Relationship info
00093   info.stud_ins_uid_= "";
00094   info.ser_ins_uid_ = "";
00095   info.study_id_ = "";
00096   info.series_number_ = VIL_DICOM_HEADER_UNSPECIFIED;
00097   info.acquisition_number_ = VIL_DICOM_HEADER_UNSPECIFIED;
00098   info.image_number_ = VIL_DICOM_HEADER_UNSPECIFIED;
00099   info.pat_orient_ = "";
00100   info.image_pos_.clear();
00101   info.image_orient_.clear();
00102   info.frame_of_ref_ = "";
00103   info.images_in_acq_ = VIL_DICOM_HEADER_UNSPECIFIED;
00104   info.pos_ref_ind_ = "";
00105   info.slice_location_ = VIL_DICOM_HEADER_UNSPECIFIED;
00106 
00107   // Image info
00108   info.pix_samps_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00109   info.photo_interp_ = "";
00110   info.size_x_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00111   info.size_y_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00112   info.size_z_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00113   info.high_bit_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00114   info.small_im_pix_val_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00115   info.large_im_pix_val_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00116   info.pixel_padding_val_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00117   info.window_centre_ = VIL_DICOM_HEADER_UNSPECIFIED;
00118   info.window_width_ = VIL_DICOM_HEADER_UNSPECIFIED;
00119 
00120   // Info for loading image
00121   info.spacing_x_ = VIL_DICOM_HEADER_DEFAULTSIZE_FLOAT;
00122   info.spacing_y_ = VIL_DICOM_HEADER_DEFAULTSIZE_FLOAT;
00123   info.spacing_slice_ = VIL_DICOM_HEADER_DEFAULTSIZE_FLOAT;
00124   info.res_intercept_ = VIL_DICOM_HEADER_DEFAULTINTERCEPT;
00125   info.res_slope_ = VIL_DICOM_HEADER_DEFAULTSLOPE;
00126   info.pix_rep_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00127   info.stored_bits_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00128   info.allocated_bits_ = VIL_DICOM_HEADER_UNSPECIFIED_UNSIGNED;
00129 }
00130 
00131 
00132 //================================================================
00133 // Default constructor
00134 //================================================================
00135 vil_dicom_header_format::vil_dicom_header_format() :
00136 info_valid_(false),
00137 file_endian_(VIL_DICOM_HEADER_DEUNKNOWN),
00138 image_type_(VIL_DICOM_HEADER_DITUNKNOWN)
00139 {
00140   // Work out the endianism of this architecture
00141   endian_ = calculateEndian();
00142 }
00143 
00144 //================================================================
00145 
00146 vil_dicom_header_format::~vil_dicom_header_format()
00147 {
00148   // Do Nothing
00149 }
00150 
00151 //================================================================
00152 
00153 bool vil_dicom_header_format::isDicomFormat(vil_stream &fs)
00154 {
00155   vil_dicom_header_type dtype;
00156 
00157   dtype = determineFileType(fs);
00158 
00159   return dtype!=VIL_DICOM_HEADER_DTUNKNOWN;
00160 }
00161 
00162 //================================================================
00163 
00164 vil_dicom_header_info vil_dicom_header_format::readHeader(vil_stream &fs)
00165 {
00166   vil_dicom_header_type dtype;
00167 
00168   // Clear the current header
00169   clearInfo();
00170 
00171   dtype = determineFileType(fs);
00172   // Check if the file is dicom first
00173   if (dtype != VIL_DICOM_HEADER_DTUNKNOWN)
00174   {
00175     last_read_.file_type_ = dtype;
00176     last_read_.sys_endian_ = systemEndian();
00177 
00178     if (dtype == VIL_DICOM_HEADER_DTPART10)
00179     {
00180       file_endian_ = determineMetaInfo(fs);
00181     }
00182 
00183     last_read_.file_endian_ = fileEndian();
00184     last_read_.image_type_ = imageType();
00185 
00186     readHeaderElements(fs);
00187 
00188     info_valid_ = true;
00189   } // End of if (dtype != VIL_DICOM_HEADER_DTUNKNOWN)
00190   else // It's not a dicom file, so can't read
00191   {
00192     vcl_cerr<<"Unknown file type - not a DICOM file...\n"
00193             <<"File header not read\n";
00194   }
00195   return last_read_;
00196 }
00197 
00198 //================================================================
00199 
00200 vil_dicom_header_info vil_dicom_header_format::lastHeader(void)
00201 {
00202   return last_read_;
00203 }
00204 
00205 //================================================================
00206 
00207 bool vil_dicom_header_format::headerValid(void)
00208 {
00209 return info_valid_;
00210 }
00211 
00212 //================================================================
00213 
00214 vil_dicom_header_endian vil_dicom_header_format::systemEndian(void)
00215 {
00216   return endian_;
00217 }
00218 
00219 //================================================================
00220 
00221 vil_dicom_header_endian vil_dicom_header_format::fileEndian(void)
00222 {
00223   return file_endian_;
00224 }
00225 
00226 //================================================================
00227 
00228 vil_dicom_header_image_type vil_dicom_header_format::imageType(void)
00229 {
00230   return image_type_;
00231 }
00232 
00233 //================================================================
00234 
00235 vil_dicom_header_type vil_dicom_header_format::determineFileType(vil_stream &fs)
00236 {
00237   vil_dicom_header_type result = VIL_DICOM_HEADER_DTUNKNOWN;
00238 
00239   // Check the file is open, otherwise fail - the vcl_fstream should
00240   // be controlled outside of this class
00241   if (fs.ok())
00242   {
00243     // There are four possibilities:
00244     // The file is Part10 with 128 byte pre-amble
00245     // The file is Part10 with no pre-amble
00246     // The file is a non-Part10 dicom file
00247     // The file is not a dicom file (or can't be determined as such)
00248     char dicm_read[5];
00249     vcl_string dicm_test;
00250 
00251     // Skip 128 byte pre-amble and test for DICM again
00252     fs.seek(128);
00253     fs.read(dicm_read,4);
00254     dicm_read[4]=0;
00255     dicm_test=dicm_read;
00256 
00257     if (dicm_test == "DICM")
00258     {
00259       result = VIL_DICOM_HEADER_DTPART10;
00260     }
00261     else
00262     {
00263       // Read the first four chars and see if they are the letters
00264       // DICM
00265       fs.seek(0);
00266       fs.read(dicm_read,4);
00267       dicm_read[4]=0;    // Null terminate
00268       dicm_test=dicm_read;
00269 
00270       if (dicm_test == "DICM")
00271       {
00272         result = VIL_DICOM_HEADER_DTPART10;
00273       }
00274       else
00275       {
00276         // Some other format - test it with both little and
00277         // big endian
00278         int num_tries = 0;
00279         bool known = false;
00280         vil_dicom_header_endian old_endian = file_endian_;
00281         file_endian_ = VIL_DICOM_HEADER_DEBIGENDIAN;
00282 
00283         while (num_tries < 2 && !known)
00284         {
00285           // Go back to the beginning and search for the
00286           // first element of the Identifying group
00287           fs.seek(0);
00288           vxl_uint_16 group, element;
00289           vxl_uint_32 data_block_size, num_elements;
00290 
00291           fs.read(&group, sizeof(vxl_uint_16));
00292           group = shortSwap(group);
00293           fs.read(&element, sizeof(vxl_uint_16));
00294           element = shortSwap(element);
00295           fs.read(&data_block_size, sizeof(vxl_uint_32));
00296           data_block_size = intSwap(data_block_size);
00297           if (data_block_size > 0x1000000) {
00298             vcl_cerr<< __FILE__ << ": " << __LINE__ << " : WARNING:\n"
00299                     <<"data_block_size=" << data_block_size << " is most probably too large\n";
00300             break;
00301           }
00302 
00303           num_elements = 0;
00304 
00305           while (group < VIL_DICOM_HEADER_IDENTIFYINGGROUP &&
00306                  num_elements < VIL_DICOM_HEADER_MAXHEADERSIZE &&
00307                  fs.ok())
00308           {
00309             // It's not what we want, so skip it and
00310             // get the next one
00311             fs.seek(data_block_size + fs.tell());
00312 
00313             fs.read(&group, sizeof(vxl_uint_16));
00314             group = shortSwap(group);
00315             fs.read(&element, sizeof(vxl_uint_16));
00316             element = shortSwap(element);
00317             fs.read(&data_block_size, sizeof(vxl_uint_32));
00318             data_block_size = intSwap(data_block_size);
00319             if (data_block_size > 0x1000000) {
00320               vcl_cerr<< __FILE__ << ": " << __LINE__ << " : WARNING:\n"
00321                       <<"data_block_size=" << data_block_size << " is most probably too large\n";
00322               break;
00323             }
00324 
00325             num_elements++;
00326           } // End of while (group...)
00327 
00328           // Check the elements read and see if it fits
00329           // with a known header
00330           if (group == VIL_DICOM_HEADER_IDENTIFYINGGROUP)
00331           {
00332             // First, standard non-Part10 header
00333             if (element == VIL_DICOM_HEADER_IDGROUPLENGTH &&
00334                 data_block_size == 4)
00335             {
00336               // Put the file back at the beginning
00337               fs.seek(0);
00338               result = VIL_DICOM_HEADER_DTNON_PART10;
00339               known = true;
00340             } // End of if (element...)
00341             // Now a non-standard non-Part10
00342             else if (element == VIL_DICOM_HEADER_IDIMAGETYPE ||
00343                      element == VIL_DICOM_HEADER_IDLENGTHTOEND ||
00344                      element == VIL_DICOM_HEADER_IDSPECIFICCHARACTER)
00345             {
00346               // Put the file back at the beginning
00347               fs.seek(0);
00348               result = VIL_DICOM_HEADER_DTNON_PART10;
00349               known = true;
00350             } // End of else if (element...)
00351           } // End of if (group == VIL_DICOM_HEADER_IDENTIFYINGGROUP)
00352 
00353           if (!known)
00354           {
00355             file_endian_ = VIL_DICOM_HEADER_DELITTLEENDIAN;
00356           }
00357 
00358           num_tries++;
00359         } // End of while (num_tries < 2 && !known)
00360 
00361         if (!known)
00362         {
00363           file_endian_ = old_endian;
00364         }
00365       } // End of else
00366     } // End of else
00367   } // End of if (fs.ok())
00368   else
00369   {
00370     vcl_cerr << "File not open for reading:\n"
00371              << "vil_dicom_header_format::determineFileType()\n";
00372   } // End of else
00373 
00374   return result;
00375 }
00376 
00377 //================================================================
00378 
00379 void vil_dicom_header_format::readHeaderElements(vil_stream &fs)
00380 {
00381   vxl_uint_16 group, element;  // The groups and elements read from the header part of the dicom file
00382   vxl_uint_32 data_block_size; // The size of the information held for this group/element pair
00383   vcl_cerr << "vil_dicom_header_format::readHeaderElements - Deprecated function called - use the DCMTK code instead!";
00384   vcl_abort();
00385 
00386   // Read the first group/element pair
00387   fs.read(&group, sizeof(vxl_uint_16));
00388   fs.read(&element, sizeof(vxl_uint_16));
00389 
00390   // Swap them if necessary
00391   group = shortSwap(group);
00392   element = shortSwap(element);
00393 
00394   // Loop until the file ends (unexpectedly!) or the
00395   // pixel data is found
00396   while (fs.ok() && !pixelDataFound(group, element))
00397   {
00398     if (sizeof(vxl_uint_32) != fs.read(&data_block_size, sizeof(vxl_uint_32)))
00399       break;
00400     data_block_size = intSwap(data_block_size);
00401     if (data_block_size > 0x1000000) {
00402       vcl_cerr<< __FILE__ << ": " << __LINE__ << " : WARNING:\n"
00403               <<"data_block_size=" << data_block_size << " is most probably too large\n";
00404       break;
00405     }
00406     convertValueRepresentation(data_block_size, fs);
00407 
00408     switch (group)
00409     {
00410      // Read identifying info
00411      case VIL_DICOM_HEADER_IDENTIFYINGGROUP:
00412       readIdentifyingElements(element, data_block_size, fs);
00413       break;
00414 
00415      // Read the patient info
00416      case VIL_DICOM_HEADER_PATIENTINFOGROUP:
00417       readPatientElements(element, data_block_size, fs);
00418       break;
00419 
00420      case VIL_DICOM_HEADER_ACQUISITIONGROUP:
00421       readAcquisitionElements(element, data_block_size, fs);
00422       break;
00423 
00424      case VIL_DICOM_HEADER_RELATIONSHIPGROUP:
00425       readRelationshipElements(element, data_block_size, fs);
00426       break;
00427 
00428      case VIL_DICOM_HEADER_IMAGEGROUP:
00429       readImageElements(element, data_block_size, fs);
00430       break;
00431 
00432      case VIL_DICOM_HEADER_DELIMITERGROUP:
00433       readDelimiterElements(element, data_block_size, fs);
00434       break;
00435 
00436      // Nothing found, so skip this data block
00437      default:
00438       fs.seek(data_block_size + fs.tell());
00439       break;
00440     } // End of switch
00441 
00442     // Read the next group and element
00443     fs.read(&group, sizeof(vxl_uint_16));
00444     fs.read(&element, sizeof(vxl_uint_16));
00445 
00446     // Swap them if necessary
00447     group = shortSwap(group);
00448     element = shortSwap(element);
00449   } // End of while
00450 
00451 
00452   // Read the final block size info - throw away!
00453   if (sizeof(vxl_uint_32) != fs.read(&data_block_size, sizeof(vxl_uint_32)))
00454     return;
00455   data_block_size = intSwap(data_block_size);
00456   if (data_block_size > 0x1000000)
00457     vcl_cerr << __FILE__ << ": " << __LINE__ << " : WARNING\n"
00458              <<"data_block_size=" << data_block_size << " is most probably too large\n";
00459   else
00460     convertValueRepresentation(data_block_size, fs);
00461 }
00462 
00463 //================================================================
00464 
00465 // These macros will be used a lot of times in the subsequent read* methods
00466 #define CASE(X,M,F) \
00467    case X : \
00468     data_p = new char[dblock_size+1]; /* Ensure room for 0 */ \
00469     if (data_p) \
00470     { \
00471       fs.read(data_p,dblock_size); \
00472       data_p[dblock_size]=0; \
00473       last_read_.M = F(data_p); \
00474     } \
00475     break
00476 
00477 #define CASE_SWP(X,M) \
00478    case X : \
00479     data_p = new char[dblock_size+1]; /* Ensure room for 0 */ \
00480     if (data_p) \
00481     { \
00482       fs.read(data_p,dblock_size); \
00483       data_p[dblock_size]=0; \
00484       charSwap(data_p, sizeof(vxl_uint_16)); \
00485       last_read_.M = *((vxl_uint_16*)data_p); \
00486     } \
00487     break
00488 
00489 void vil_dicom_header_format::readIdentifyingElements(short element,
00490                                                       int dblock_size,
00491                                                       vil_stream &fs)
00492 {
00493   // Pointer to any data read
00494   char *data_p = 0;
00495 
00496   // Check the elements
00497   switch ((vxl_uint_16)element)
00498   {
00499    CASE(VIL_DICOM_HEADER_IDIMAGETYPE,         image_id_type_, (char *)); // It's the image type
00500    CASE(VIL_DICOM_HEADER_IDSOPCLASSID,        sop_cl_uid_, (char *)); // It's the SOP class ID
00501    CASE(VIL_DICOM_HEADER_IDSOPINSTANCEID,     sop_in_uid_, (char *)); // It's the SOP instance ID
00502    CASE(VIL_DICOM_HEADER_IDSTUDYDATE,         study_date_,vcl_atol); // It's the study date
00503    CASE(VIL_DICOM_HEADER_IDSERIESDATE,        series_date_,vcl_atol); // It's the series date
00504    CASE(VIL_DICOM_HEADER_IDACQUISITIONDATE,   acquisition_date_,vcl_atol); // It's the acquisition date
00505    CASE(VIL_DICOM_HEADER_IDIMAGEDATE,         image_date_,vcl_atol); // It's the image date
00506    CASE(VIL_DICOM_HEADER_IDSTUDYTIME,         study_time_,(float)vcl_atof); // It's the study time
00507    CASE(VIL_DICOM_HEADER_IDSERIESTIME,        series_time_,(float)vcl_atof); // It's the series time
00508    CASE(VIL_DICOM_HEADER_IDACQUISITIONTIME,   acquisition_time_,(float)vcl_atof); // It's the acquisition time
00509    CASE(VIL_DICOM_HEADER_IDIMAGETIME,         image_time_,(float)vcl_atof); // It's the image time
00510    CASE(VIL_DICOM_HEADER_IDACCESSIONNUMBER,   accession_number_, (char *)); // It's the accession number
00511    CASE(VIL_DICOM_HEADER_IDMODALITY,          modality_, (char *)); // It's the imaging modality
00512    CASE(VIL_DICOM_HEADER_IDMANUFACTURER,      manufacturer_, (char *)); // It's the manufacturer name
00513    CASE(VIL_DICOM_HEADER_IDINSTITUTIONNAME,   institution_name_, (char *)); // It's the institution name
00514    CASE(VIL_DICOM_HEADER_IDINSTITUTIONADDRESS,institution_addr_, (char *)); // It's the institution address
00515    CASE(VIL_DICOM_HEADER_IDREFERRINGPHYSICIAN,ref_phys_name_, (char *)); // It's the referring physician's name
00516    CASE(VIL_DICOM_HEADER_IDSTATIONNAME,       station_name_, (char *)); // It's the imaging station name
00517    CASE(VIL_DICOM_HEADER_IDSTUDYDESCRIPTION,  study_desc_, (char *)); // It's the study description
00518    CASE(VIL_DICOM_HEADER_IDSERIESDESCRIPTION, series_desc_, (char *)); // It's the series description
00519    CASE(VIL_DICOM_HEADER_IDATTENDINGPHYSICIAN,att_phys_name_, (char *)); // It's the name of the attending physician
00520    CASE(VIL_DICOM_HEADER_IDOPERATORNAME,      operator_name_, (char *)); // It's the name of the scanner operator
00521    CASE(VIL_DICOM_HEADER_IDMANUFACTURERMODEL, model_name_, (char *)); // It's the scanner model
00522    default: // It's nothing we want, so skip it!
00523     fs.seek(dblock_size + fs.tell());
00524     break;
00525   } // End of switch
00526 
00527   delete[] data_p;
00528 }
00529 
00530 //================================================================
00531 
00532 void vil_dicom_header_format::readPatientElements(short element,
00533                                                   int dblock_size,
00534                                                   vil_stream &fs)
00535 {
00536   // Pointer to any data read
00537   char *data_p = 0;
00538 
00539   // Check the elements
00540   switch ((vxl_uint_16)element)
00541   {
00542    CASE(VIL_DICOM_HEADER_PIPATIENTNAME,     patient_name_, (char *)); // It's the patient's name
00543    CASE(VIL_DICOM_HEADER_PIPATIENTID,       patient_id_, (char *)); // It's the patient's id
00544    CASE(VIL_DICOM_HEADER_PIPATIENTBIRTHDATE,patient_dob_,vcl_atol); // It's the patient's date of birth
00545    CASE(VIL_DICOM_HEADER_PIPATIENTSEX,      patient_sex_, (char *)); // It's the patient's sex
00546    CASE(VIL_DICOM_HEADER_PIPATIENTAGE,      patient_age_, (char *)); // It's the patient's age
00547    CASE(VIL_DICOM_HEADER_PIPATIENTWEIGHT,   patient_weight_,(float)vcl_atof); // It's the patient's weight
00548    CASE(VIL_DICOM_HEADER_PIPATIENTHISTORY,  patient_hist_, (char *)); // It's the patient's history
00549    default: // It's nothing we want, so skip it!
00550     fs.seek(dblock_size + fs.tell());
00551     break;
00552   } // End of switch
00553 
00554   delete[] data_p;
00555 }
00556 
00557 //================================================================
00558 
00559 void vil_dicom_header_format::readAcquisitionElements(short element,
00560                                                       int dblock_size,
00561                                                       vil_stream &fs)
00562 {
00563   // Pointer to any data read
00564   char *data_p = 0;
00565 
00566   // Check the elements
00567   switch ((vxl_uint_16)element)
00568   {
00569    CASE(VIL_DICOM_HEADER_AQSCANNINGSEQUENCE,      scanning_seq_, (char *)); // It's the scanning sequence
00570    CASE(VIL_DICOM_HEADER_AQSEQUENCEVARIANT,       sequence_var_, (char *)); // It's the sequence variant
00571    CASE(VIL_DICOM_HEADER_AQSCANOPTIONS,           scan_options_, (char *)); // It's the scan options
00572    CASE(VIL_DICOM_HEADER_AQMRACQUISITIONTYPE,     mr_acq_type_, (char *)); // It's the MR acquisition type
00573    CASE(VIL_DICOM_HEADER_AQSEQUENCENAME,          sequence_name_, (char *)); // It's the sequence name
00574    CASE(VIL_DICOM_HEADER_AQANGIOFLAG,             angio_flag_, (char *)); // It's the angio flag
00575    CASE(VIL_DICOM_HEADER_AQSLICETHICKNESS,        slice_thickness_,(float)vcl_atof); // It's the slice thickness
00576    CASE(VIL_DICOM_HEADER_AQREPETITIONTIME,        repetition_time_,(float)vcl_atof); // It's the repetition time
00577    CASE(VIL_DICOM_HEADER_AQECHOTIME,              echo_time_,(float)vcl_atof); // It's the echo time
00578    CASE(VIL_DICOM_HEADER_AQINVERSIONTIME,         inversion_time_,(float)vcl_atof); // It's the inversion time
00579    CASE(VIL_DICOM_HEADER_AQNUMBEROFAVERAGES,      number_of_averages_,(float)vcl_atof); // It's the number of averages
00580    CASE(VIL_DICOM_HEADER_AQECHONUMBERS,           echo_numbers_,vcl_atoi); // It's the echo numbers
00581    CASE(VIL_DICOM_HEADER_AQMAGNETICFIELDSTRENGTH, mag_field_strength_,(float)vcl_atof); // It's the magnetic field strength
00582    CASE(VIL_DICOM_HEADER_AQSLICESPACING,          spacing_slice_,(float)vcl_atof); // It's the slice spacing
00583    CASE(VIL_DICOM_HEADER_AQECHOTRAINLENGTH,       echo_train_length_,(int)vcl_atoi); // It's the echo train length
00584    CASE(VIL_DICOM_HEADER_AQPIXELBANDWIDTH,        pixel_bandwidth_,(float)vcl_atof); // It's the pixel bandwidth
00585    CASE(VIL_DICOM_HEADER_AQSOFTWAREVERSION,       software_vers_, (char *)); // It's the scanner software version
00586    CASE(VIL_DICOM_HEADER_AQPROTOCOLNAME,          protocol_name_, (char *)); // It's the protocol name
00587    CASE(VIL_DICOM_HEADER_AQHEARTRATE,             heart_rate_,vcl_atoi); // It's the heart rate
00588    CASE(VIL_DICOM_HEADER_AQCARDIACNUMBEROFIMAGES, card_num_images_,vcl_atoi); // It's the cardiac number of images
00589    CASE(VIL_DICOM_HEADER_AQTRIGGERWINDOW,         trigger_window_,vcl_atoi); // It's the trigger window
00590    CASE(VIL_DICOM_HEADER_AQRECONTRUCTIONDIAMETER, reconst_diameter_,(float)vcl_atof); // It's the reconstruction diameter
00591    CASE(VIL_DICOM_HEADER_AQRECEIVINGCOIL,         receiving_coil_, (char *)); // It's the receiving coil
00592    CASE(VIL_DICOM_HEADER_AQPHASEENCODINGDIRECTION,phase_enc_dir_, (char *)); // It's the phase encoding direction
00593    CASE(VIL_DICOM_HEADER_AQFLIPANGLE,             flip_angle_,(float)vcl_atof); // It's the flip angle
00594    CASE(VIL_DICOM_HEADER_AQSAR,                   sar_,(float)vcl_atof); // It's the sar
00595    CASE(VIL_DICOM_HEADER_AQPATIENTPOSITION,       patient_pos_, (char *)); // It's the patient position
00596    default: // It's nothing we want, so skip it!
00597     fs.seek(dblock_size + fs.tell());
00598     break;
00599   } // End of switch
00600 
00601   delete[] data_p;
00602 }
00603 
00604 //================================================================
00605 
00606 void vil_dicom_header_format::readRelationshipElements(short element,
00607                                                        int dblock_size,
00608                                                        vil_stream &fs)
00609 {
00610   // Pointer to any data read
00611   char *data_p = 0;
00612 
00613   // Check the elements
00614   switch ((vxl_uint_16)element)
00615   {
00616    CASE(VIL_DICOM_HEADER_RSSTUDYINSTANCEUID,   stud_ins_uid_, (char *)); // It's the study instance id
00617    CASE(VIL_DICOM_HEADER_RSSERIESINSTANCEUID,  ser_ins_uid_, (char *)); // It's the series instance id
00618    CASE(VIL_DICOM_HEADER_RSSTUDYID,            study_id_, (char *)); // It's the study id
00619    CASE(VIL_DICOM_HEADER_RSSERIESNUMBER,       series_number_,vcl_atoi); // It's the series number
00620    CASE(VIL_DICOM_HEADER_RSAQUISITIONNUMBER,   acquisition_number_,vcl_atoi); // It's the acqusition number
00621    CASE(VIL_DICOM_HEADER_RSIMAGENUMBER,        image_number_,vcl_atoi); // It's the image number
00622    CASE(VIL_DICOM_HEADER_RSPATIENTORIENTATION, pat_orient_, (char *)); // It's the patient orientation
00623 //   CASE(VIL_DICOM_HEADER_RSIMAGEPOSITION,      image_pos_, (float)vcl_atof); // It's the image position
00624 //   CASE(VIL_DICOM_HEADER_RSIMAGEORIENTATION,   image_orient_, (float)vcl_atof); // It's the image orientation
00625    CASE(VIL_DICOM_HEADER_RSFRAMEOFREFERENCEUID,frame_of_ref_, (char *)); // It's the frame of reference uid
00626    CASE(VIL_DICOM_HEADER_RSIMAGESINACQUISITION,images_in_acq_,vcl_atoi); // It's the number of images in the acquisition
00627    CASE(VIL_DICOM_HEADER_RSPOSITIONREFERENCE,  pos_ref_ind_, (char *)); // It's the position reference
00628    CASE(VIL_DICOM_HEADER_RSSLICELOCATION,      slice_location_,(float) vcl_atof); // It's the slice location
00629    default: // It's nothing we want, so skip it!
00630     fs.seek(dblock_size + fs.tell());
00631     break;
00632   } // End of switch
00633 
00634   delete[] data_p;
00635 }
00636 
00637 
00638 //================================================================
00639 
00640 void vil_dicom_header_format::readImageElements(short element,
00641                                                 int dblock_size,
00642                                                 vil_stream &fs)
00643 {
00644     // Pointer to any data read
00645   char *data_p = 0;
00646 
00647   // Check the elements
00648   switch ((vxl_uint_16)element)
00649   {
00650    CASE_SWP(VIL_DICOM_HEADER_IMSAMPLESPERPIXEL,    pix_samps_); // It's the samples per pixel
00651    CASE(VIL_DICOM_HEADER_IMPHOTOMETRICINTERP,      photo_interp_, (char *)); // It's the photometric interpretation
00652    CASE_SWP(VIL_DICOM_HEADER_IMROWS,               size_y_); // It's the rows
00653    CASE_SWP(VIL_DICOM_HEADER_IMCOLUMNS,            size_x_); // It's the columns
00654    CASE_SWP(VIL_DICOM_HEADER_IMPLANES,             size_z_); // It's the planes
00655    CASE_SWP(VIL_DICOM_HEADER_IMBITSALLOCATED,      allocated_bits_); // It's the allocated bits
00656    CASE_SWP(VIL_DICOM_HEADER_IMBITSSTORED,         stored_bits_); // It's the stored bits info
00657    CASE_SWP(VIL_DICOM_HEADER_IMHIGHBIT,            high_bit_); // It's the high bit
00658    CASE_SWP(VIL_DICOM_HEADER_IMPIXELREPRESENTATION,pix_rep_); // It's the pixel representation
00659    CASE_SWP(VIL_DICOM_HEADER_IMSMALLIMPIXELVALUE,  small_im_pix_val_); // It's the smallest image pixel value
00660    CASE_SWP(VIL_DICOM_HEADER_IMLARGEIMPIXELVALUE,  large_im_pix_val_); // It's the largest image pixel value
00661    CASE_SWP(VIL_DICOM_HEADER_IMPIXELPADDINGVALUE,  pixel_padding_val_); // It's the pixel padding value
00662    CASE(VIL_DICOM_HEADER_IMWINDOWCENTER,           window_centre_,(float) vcl_atof); // It's the window centre
00663    CASE(VIL_DICOM_HEADER_IMWINDOWWIDTH,            window_width_,(float) vcl_atof); // It's the window width
00664    CASE(VIL_DICOM_HEADER_IMRESCALEINTERCEPT,       res_intercept_,(float) vcl_atof); // It's the rescale intercept
00665    CASE(VIL_DICOM_HEADER_IMRESCALESLOPE,           res_slope_,(float) vcl_atof); // It's the rescale slope
00666    case VIL_DICOM_HEADER_IMPIXELSPACING : // It's the pixel spacing
00667     data_p = new char[dblock_size+1];
00668     if (data_p)
00669     {
00670       fs.read(data_p,dblock_size);
00671       data_p[dblock_size]=0;
00672       last_read_.spacing_x_ = (float) vcl_atof(data_p);
00673 
00674       // The y size should come after a '\'
00675       // If only a 0 is found, ysize = xsize
00676       char gone = 'x';
00677       while (gone != 0 && gone != '\\')
00678       {
00679         gone = data_p[0];
00680         for (int i=0; i<dblock_size; i++)
00681           data_p[i] = data_p[i+1];
00682       }
00683       if (gone == '\\')
00684         last_read_.spacing_y_ = (float) vcl_atof(data_p);
00685       else
00686         last_read_.spacing_y_ = (float) last_read_.spacing_x_;
00687     }
00688     break;
00689 
00690    default: // It's nothing we want, so skip it!
00691     fs.seek(dblock_size + fs.tell());
00692     break;
00693   } // End of switch
00694 
00695   delete[] data_p;
00696 }
00697 
00698 //================================================================
00699 
00700 void vil_dicom_header_format::readDelimiterElements(short element,
00701                                                     int dblock_size,
00702                                                     vil_stream &fs)
00703 {
00704   // Check the elements
00705   switch ((vxl_uint_16)element)
00706   {
00707    case VIL_DICOM_HEADER_DLITEM:
00708    case VIL_DICOM_HEADER_DLITEMDELIMITATIONITEM:
00709    case VIL_DICOM_HEADER_DLSEQDELIMITATIONITEM:
00710     // There's no data block
00711     break;
00712     // It's nothing we want, so skip it!
00713    default:
00714     fs.seek(dblock_size + fs.tell());
00715     break;
00716   } // End of switch
00717 }
00718 
00719 //================================================================
00720 
00721 bool vil_dicom_header_format::convertValueRepresentation(unsigned int &dblock_size,
00722                                                          vil_stream &fs)
00723 {
00724   bool result = false;
00725   vcl_string first, last;
00726   char temp[3];
00727 
00728   // Union to convert the int to chars
00729   union int_char
00730   {
00731     vxl_uint_32 int_val;
00732     char char_val[4];
00733   } conv_dblock;
00734 
00735   if (last_read_.file_type_ != VIL_DICOM_HEADER_DTUNKNOWN)
00736   {
00737     conv_dblock.int_val = dblock_size;
00738 
00739     // Create the strings to check (the latter two positions in
00740     // the vcl_string are swapped in case of little endian-ness)
00741     temp[0] = conv_dblock.char_val[0];
00742     temp[1] = conv_dblock.char_val[1];
00743     temp[2] = 0;
00744 
00745     first = temp;
00746 
00747     temp[0] = conv_dblock.char_val[3];
00748     temp[1] = conv_dblock.char_val[2];
00749 
00750     last = temp;
00751 
00752     // Check if VR is a nested sequence (SQ)
00753     if (first == VIL_DICOM_HEADER_SEQUENCE || last == VIL_DICOM_HEADER_SEQUENCE)
00754     {
00755       fs.read(&dblock_size, sizeof(int));
00756       dblock_size = 0;
00757       result = true;
00758     } // End of if (first...)
00759     else if (first == VIL_DICOM_HEADER_OTHERBYTE ||
00760              first == VIL_DICOM_HEADER_OTHERWORD ||
00761              last == VIL_DICOM_HEADER_OTHERBYTE  ||
00762              last == VIL_DICOM_HEADER_OTHERWORD)
00763     {
00764       fs.read(&dblock_size, sizeof(int));
00765       dblock_size = intSwap(dblock_size);
00766       result = true;
00767     } // End of else if (first...)
00768     else if (dblock_size == VIL_DICOM_HEADER_ALLSET)
00769     {
00770       dblock_size = 0;
00771       result = true;
00772     } // End of else if (dblock_size == VIL_DICOM_HEADER_ALLSET)
00773     else if (first == VIL_DICOM_HEADER_APPLICATIONENTRY    ||
00774              first == VIL_DICOM_HEADER_AGESTRING           ||
00775              first == VIL_DICOM_HEADER_ATTRIBUTETAG        ||
00776              first == VIL_DICOM_HEADER_CODESTRING          ||
00777              first == VIL_DICOM_HEADER_DATE                ||
00778              first == VIL_DICOM_HEADER_DECIMALSTRING       ||
00779              first == VIL_DICOM_HEADER_DATETIME            ||
00780              first == VIL_DICOM_HEADER_FLOATINGPOINTDOUBLE ||
00781              first == VIL_DICOM_HEADER_FLOATINGPOINTSINGLE ||
00782              first == VIL_DICOM_HEADER_INTEGERSTRING       ||
00783              first == VIL_DICOM_HEADER_LONGSTRING          ||
00784              first == VIL_DICOM_HEADER_LONGTEXT            ||
00785              first == VIL_DICOM_HEADER_PERSONNAME          ||
00786              first == VIL_DICOM_HEADER_SHORTSTRING         ||
00787              first == VIL_DICOM_HEADER_SIGNEDLONG          ||
00788              first == VIL_DICOM_HEADER_SIGNEDSHORT         ||
00789              first == VIL_DICOM_HEADER_SHORTTEXT           ||
00790              first == VIL_DICOM_HEADER_TIME                ||
00791              first == VIL_DICOM_HEADER_UNIQUEIDENTIFIER    ||
00792              first == VIL_DICOM_HEADER_UNSIGNEDLONG        ||
00793              first == VIL_DICOM_HEADER_UNSIGNEDSHORT)
00794     {
00795       if (last_read_.sys_endian_ == VIL_DICOM_HEADER_DELITTLEENDIAN)
00796       {
00797         dblock_size = (unsigned int)((256*conv_dblock.char_val[3]) + conv_dblock.char_val[2]);
00798       }
00799       else
00800       {
00801         dblock_size = (unsigned int)((256*conv_dblock.char_val[2]) + conv_dblock.char_val[3]);
00802       }
00803 
00804       result = true;
00805     } // End of else if (first...)
00806     else if (last == VIL_DICOM_HEADER_APPLICATIONENTRY    ||
00807              last == VIL_DICOM_HEADER_AGESTRING           ||
00808              last == VIL_DICOM_HEADER_ATTRIBUTETAG        ||
00809              last == VIL_DICOM_HEADER_CODESTRING          ||
00810              last == VIL_DICOM_HEADER_DATE                ||
00811              last == VIL_DICOM_HEADER_DECIMALSTRING       ||
00812              last == VIL_DICOM_HEADER_DATETIME            ||
00813              last == VIL_DICOM_HEADER_FLOATINGPOINTDOUBLE ||
00814              last == VIL_DICOM_HEADER_FLOATINGPOINTSINGLE ||
00815              last == VIL_DICOM_HEADER_INTEGERSTRING       ||
00816              last == VIL_DICOM_HEADER_LONGSTRING          ||
00817              last == VIL_DICOM_HEADER_LONGTEXT            ||
00818              last == VIL_DICOM_HEADER_PERSONNAME          ||
00819              last == VIL_DICOM_HEADER_SHORTSTRING         ||
00820              last == VIL_DICOM_HEADER_SIGNEDLONG          ||
00821              last == VIL_DICOM_HEADER_SIGNEDSHORT         ||
00822              last == VIL_DICOM_HEADER_SHORTTEXT           ||
00823              last == VIL_DICOM_HEADER_TIME                ||
00824              last == VIL_DICOM_HEADER_UNIQUEIDENTIFIER    ||
00825              last == VIL_DICOM_HEADER_UNSIGNEDLONG        ||
00826              last == VIL_DICOM_HEADER_UNSIGNEDSHORT)
00827     {
00828       if (last_read_.sys_endian_ == VIL_DICOM_HEADER_DELITTLEENDIAN)
00829       {
00830         dblock_size = (unsigned int)((256*conv_dblock.char_val[1]) + conv_dblock.char_val[0]);
00831       }
00832       else
00833       {
00834         dblock_size = (unsigned int)((256*conv_dblock.char_val[0]) + conv_dblock.char_val[1]);
00835       }
00836 
00837       result = true;
00838     } // End of else if (last...)
00839   } // End of if (last_read_.file_type_ != VIL_DICOM_HEADER_DTUNKNOWN)
00840 
00841   return result;
00842 }
00843 
00844 //================================================================
00845 
00846 bool vil_dicom_header_format::pixelDataFound(short group, short element)
00847 {
00848   bool result = false;
00849 
00850   // Check if it's the pixel data
00851   if ((vxl_uint_16)group == VIL_DICOM_HEADER_PIXELGROUP &&
00852       (vxl_uint_16)element == VIL_DICOM_HEADER_PXPIXELDATA)
00853   {
00854     result = true;
00855   }
00856 
00857   return result;
00858 }
00859 
00860 //================================================================
00861 
00862 void vil_dicom_header_format::clearInfo(void)
00863 {
00864   vil_dicom_header_info_clear( last_read_ );
00865 
00866   // And make it invalid
00867   info_valid_ = false;
00868 }
00869 
00870 //================================================================
00871 
00872 vil_dicom_header_endian vil_dicom_header_format::calculateEndian(void)
00873 {
00874   // Create a union to test endian
00875   union int_byte
00876   {
00877     vxl_uint_32 int_val;
00878     vxl_byte by_val[4];
00879   } calc_endian;
00880 
00881   // Put 1 into the union
00882   calc_endian.int_val = 1;
00883 
00884   // Test which byte has the value 1 in it
00885   return calc_endian.by_val[0] == 1 ?
00886     VIL_DICOM_HEADER_DELITTLEENDIAN :
00887     VIL_DICOM_HEADER_DEBIGENDIAN;
00888 }
00889 
00890 //===============================================================
00891 
00892 vil_dicom_header_endian vil_dicom_header_format::determineMetaInfo(vil_stream &fs)
00893 {
00894   vil_dicom_header_endian ret_end = VIL_DICOM_HEADER_DELITTLEENDIAN; // Assume little if none found
00895   //vil_dicom_header_endian ret_end = VIL_DICOM_HEADER_DEBIGENDIAN;
00896 
00897   vxl_uint_16 group, element;
00898   vxl_uint_32 data_block_size;
00899   vil_streampos ret_pos = fs.tell(); // Maintain the file position
00900 
00901   // The first section of the file header is always little endian,
00902   // so set the file endian
00903   file_endian_ = VIL_DICOM_HEADER_DELITTLEENDIAN;
00904   image_type_ = VIL_DICOM_HEADER_DITUNKNOWN;
00905 
00906   // Read the next group
00907   fs.read(&group,sizeof(vxl_uint_16));
00908   group = shortSwap(group);
00909 
00910   while (fs.ok() && group <= VIL_DICOM_HEADER_METAFILEGROUP)
00911   {
00912     // Read the element
00913 
00914     fs.read(&element,sizeof(vxl_uint_16));
00915     element = shortSwap(element);
00916 
00917     // Read the data block size
00918     if (sizeof(vxl_uint_32) != fs.read(&data_block_size, sizeof(vxl_uint_32)))
00919       break;
00920 
00921     data_block_size = intSwap(data_block_size);
00922 
00923     if (data_block_size > 0x1000000) {
00924       vcl_cerr<< __FILE__ << ": " << __LINE__ << " : WARNING:\n"
00925               <<"data_block_size=" << data_block_size << " is most probably too large\n";
00926       break;
00927     }
00928 
00929     convertValueRepresentation(data_block_size,fs);
00930 
00931     if (group == VIL_DICOM_HEADER_METAFILEGROUP &&
00932         element == VIL_DICOM_HEADER_MFTRANSFERSYNTAX)
00933     {
00934       // This tells us the transfer syntax for the file
00935       char * tfx_type = new char[data_block_size+1]; // Ensure room for 0
00936       if (tfx_type)
00937       {
00938         fs.read(tfx_type, data_block_size);
00939         tfx_type[data_block_size]=0;
00940 
00941         // Now see what it is
00942 
00943         vcl_string temp = tfx_type;
00944         delete [] tfx_type;
00945 
00946         if (temp == VIL_DICOM_HEADER_IMPLICITLITTLE ||
00947             temp == VIL_DICOM_HEADER_EXPLICITLITTLE)
00948         {
00949           // Little endian
00950           ret_end = VIL_DICOM_HEADER_DELITTLEENDIAN;
00951         }
00952         else if (temp == VIL_DICOM_HEADER_EXPLICITBIG)
00953         {
00954           // Big endian
00955           ret_end = VIL_DICOM_HEADER_DEBIGENDIAN;
00956         }
00957         else if (temp == VIL_DICOM_HEADER_JPEGBASELINE_P1)
00958         {
00959           // Jpeg Baseline
00960           image_type_ = VIL_DICOM_HEADER_DITJPEGBASE;
00961         }
00962         else if (temp == VIL_DICOM_HEADER_JPEGDEFLOSSY_P2_4 ||
00963                  temp == VIL_DICOM_HEADER_JPEGEXTENDED_P3_5)
00964         {
00965           // Jpeg extended lossy
00966           image_type_ = VIL_DICOM_HEADER_DITJPEGEXTLOSSY;
00967         }
00968         else if (temp == VIL_DICOM_HEADER_JPEGSPECTRAL_P6_8 ||
00969                  temp == VIL_DICOM_HEADER_JPEGSPECTRAL_P7_9)
00970         {
00971           // Jpeg spectral selection non-hierarchical
00972           image_type_ = VIL_DICOM_HEADER_DITJPEGSPECNH;
00973         }
00974         else if (temp == VIL_DICOM_HEADER_JPEGFULLPROG_P10_12 ||
00975                  temp == VIL_DICOM_HEADER_JPEGFULLPROG_P11_13)
00976         {
00977           // Full progression non-hierarchical
00978           image_type_ = VIL_DICOM_HEADER_DITJPEGFULLNH;
00979         }
00980         else if (temp == VIL_DICOM_HEADER_JPEGLOSSLESS_P14 ||
00981                  temp == VIL_DICOM_HEADER_JPEGLOSSLESS_P15)
00982         {
00983           // Lossless non-hierarchical
00984           image_type_ = VIL_DICOM_HEADER_DITJPEGLOSSLNH;
00985         }
00986         else if (temp == VIL_DICOM_HEADER_JPEGEXTHIER_P16_18 ||
00987                  temp == VIL_DICOM_HEADER_JPEGEXTHIER_P17_19)
00988         {
00989           // Extended hierarchical
00990           image_type_ = VIL_DICOM_HEADER_DITJPEGEXTHIER;
00991         }
00992         else if (temp == VIL_DICOM_HEADER_JPEGSPECHIER_P20_22 ||
00993                  temp == VIL_DICOM_HEADER_JPEGSPECHIER_P21_23)
00994         {
00995           // Spectral selection hierarchical
00996           image_type_ = VIL_DICOM_HEADER_DITJPEGSPECHIER;
00997         }
00998         else if (temp == VIL_DICOM_HEADER_JPEGFULLHIER_P24_26 ||
00999                  temp == VIL_DICOM_HEADER_JPEGFULLHIER_P25_27)
01000         {
01001           // Full progression hierarchical
01002           image_type_ = VIL_DICOM_HEADER_DITJPEGFULLHIER;
01003         }
01004         else if (temp == VIL_DICOM_HEADER_JPEGLLESSHIER_P28 ||
01005                  temp == VIL_DICOM_HEADER_JPEGLLESSHIER_P29)
01006         {
01007           // Lossless hierarchical
01008           image_type_ = VIL_DICOM_HEADER_DITJPEGLOSSLHIER;
01009         }
01010         else if (temp == VIL_DICOM_HEADER_JPEGLLESSDEF_P14_SV1)
01011         {
01012           // The default for lossless jpeg
01013           image_type_ = VIL_DICOM_HEADER_DITJPEGLOSSLDEF;
01014         }
01015         else if (temp == VIL_DICOM_HEADER_RLELOSSLESS)
01016         {
01017           // RLE encapsulated
01018           image_type_ = VIL_DICOM_HEADER_DITRLE;
01019         }
01020 
01021       } // End of if (tfx_type)
01022     } // End of if (group...)
01023     else if (group == VIL_DICOM_HEADER_DELIMITERGROUP &&
01024              (element == VIL_DICOM_HEADER_DLITEM ||
01025               element == VIL_DICOM_HEADER_DLITEMDELIMITATIONITEM ||
01026               element == VIL_DICOM_HEADER_DLSEQDELIMITATIONITEM))
01027     {
01028       // Do nothing
01029     }
01030     else
01031     {
01032         // Ignore the data that's there
01033         fs.seek(data_block_size + fs.tell());
01034     }
01035 
01036     ret_pos = fs.tell();
01037 
01038     // Read the next group
01039 
01040     fs.read(&group,sizeof(vxl_uint_16));
01041     group = shortSwap(group);
01042 
01043   } // End of while
01044 
01045   // Reset the pointer before the last read group
01046   fs.seek(ret_pos);
01047 
01048   return ret_end;
01049 }
01050 
01051 //===============================================================
01052 
01053 vxl_uint_16 vil_dicom_header_format::shortSwap(vxl_uint_16 short_in)
01054 {
01055   vxl_uint_16 result = short_in;
01056 
01057   // Only swap if the architecture is different to the
01058   // file (the logic means that if one is unknown it swaps,
01059   // if both are unknown, it doesnt)
01060   if (file_endian_ != endian_)
01061   {
01062     // Create a short unioned with two chars
01063     union short_char
01064     {
01065       vxl_uint_16 short_val;
01066       vxl_byte byte_val[2];
01067     } short_swap;
01068 
01069     // Set the swapper
01070     short_swap.short_val = short_in;
01071 
01072     // Swap them over
01073     vxl_byte temp = short_swap.byte_val[0];
01074     short_swap.byte_val[0]=short_swap.byte_val[1];
01075     short_swap.byte_val[1]=temp;
01076 
01077     result = short_swap.short_val;
01078   } // End of if (file_endian_ != endian_)
01079 
01080   return result;
01081 }
01082 
01083 //===============================================================
01084 
01085 vxl_uint_32 vil_dicom_header_format::intSwap(vxl_uint_32 int_in)
01086 {
01087   vxl_uint_32 result = int_in;
01088 
01089   // Only swap if the architecture is different to the
01090   // file (the logic means that if one is unknown it swaps,
01091   // if both are unknown, it doesnt)
01092   if (file_endian_ != endian_)
01093   {
01094     // Create a vxl_uint_32 unioned with four chars
01095     union int_char
01096     {
01097       vxl_uint_32 int_val;
01098       vxl_byte byte_val[4];
01099     } int_swap;
01100 
01101     // Set the swapper
01102     int_swap.int_val = int_in;
01103 
01104     // Swap them over (end ones first)
01105     vxl_byte temp = int_swap.byte_val[0];
01106     int_swap.byte_val[0]=int_swap.byte_val[3];
01107     int_swap.byte_val[3]=temp;
01108 
01109     // Now the middle ones
01110     temp = int_swap.byte_val[1];
01111     int_swap.byte_val[1] = int_swap.byte_val[2];
01112     int_swap.byte_val[2] = temp;
01113 
01114     result = int_swap.int_val;
01115   } // End of if (file_endian_ != endian_)
01116 
01117   return result;
01118 }
01119 
01120 //===============================================================
01121 
01122 void vil_dicom_header_format::charSwap(char *char_in, int val_size)
01123 {
01124   // Only swap if the architecture is different to the
01125   // file (the logic means that if one is unknown it swaps,
01126   // if both are unknown, it doesnt)
01127   if (file_endian_ != endian_)
01128   {
01129     // Swap first with last, second with one-but-last, etc.
01130     for (int i=val_size/2-1; i>=0; --i)
01131     {
01132       char temp=char_in[i];
01133       char_in[i] = char_in[val_size-i-1];
01134       char_in[val_size-i-1] = temp;
01135     }
01136   }
01137 }
01138 
01139 
01140 void vil_dicom_header_print(vcl_ostream &os, const vil_dicom_header_info &s)
01141 {
01142   os << "\n\nGeneral info fields\n"
01143      << " file_type        The type of dicom file: " << s.file_type_ << vcl_endl
01144      << " sys_endian       The endian of the architecture: " << s.sys_endian_ << vcl_endl
01145      << " image_type       The encapsulated (or not) image type: " <<s.image_type_ << vcl_endl
01146 
01147      << "\n\nIdentifying fields\n"
01148      << " image_id_type    The image type from the dicom header: " << s.image_id_type_ << vcl_endl
01149      << " sop_cl_uid       The class unique id for the Service/Object Pair: " << s.sop_cl_uid_ << vcl_endl
01150      << " sop_in_uid       The instance uid for the SOP: " << s.sop_in_uid_ << vcl_endl
01151      << " study_date       The date of the study: " << s.study_date_ << vcl_endl
01152      << " series_date      The date this series was collected: " << s.series_date_ << vcl_endl
01153      << " acquisition_date The date of acquisition: " << s.acquisition_date_ << vcl_endl
01154      << " image_date       The date of this image: " << s.image_date_ << vcl_endl
01155      << " study_time       The time of the study: " << s.study_time_ << vcl_endl
01156      << " series_time      The time of the series: " << s.series_time_ << vcl_endl
01157      << " acquisition_time The time acquisition: " << s.acquisition_time_ << vcl_endl
01158      << " image_time       The time of the image: " << s.image_time_ << vcl_endl
01159      << " accession_number The accession number for this image: " << s.accession_number_ << vcl_endl
01160      << " modality         The imaging modality: " << s.modality_ << vcl_endl
01161      << " manufacturer     The name of the scanner manufacturer: " << s.manufacturer_ << vcl_endl
01162      << " institution_name The name of the institution: " << s.institution_name_ << vcl_endl
01163      << " institution_addr The address of the institution: " << s.institution_addr_ << vcl_endl
01164      << " ref_phys_name    The name of the referring physician: " << s.ref_phys_name_ << vcl_endl
01165      << " station_name     The name of the station used: " << s.station_name_ << vcl_endl
01166      << " study_desc       A description of the study: " << s.study_desc_ << vcl_endl
01167      << " series_desc      A description of the series: " << s.series_desc_ << vcl_endl
01168      << " att_phys_name    The name of the attending physician: " << s.att_phys_name_ << vcl_endl
01169      << " operator_name    The name of the MR operator: " << s.operator_name_ << vcl_endl
01170      << " model_name       The name of the MR scanner model: " << s.model_name_ << vcl_endl
01171 
01172      << "\n\nPatient info\n"
01173      << " patient_name     Patient's name: " << s.patient_name_ << vcl_endl
01174      << " patient_id       Patient's ID: " << s.patient_id_ << vcl_endl
01175      << " patient_dob      The patient's date of birth: " << s.patient_dob_ << vcl_endl
01176      << " patient_sex      The sex of the patient: " << s.patient_sex_ << vcl_endl
01177      << " patient_age      The age of the patient: " << s.patient_age_ << vcl_endl
01178      << " patient_weight_  The weight of the patient: " << s.patient_weight_ << vcl_endl
01179      << " patient_hist     Any additional patient history: " << s.patient_hist_ << vcl_endl
01180 
01181      << "\n\nAcquisition Info\n"
01182      << " scanning_seq     A description of the scanning sequence: " << s.scanning_seq_ << vcl_endl
01183      << " sequence_var     A description of the sequence variant: " << s.sequence_var_ << vcl_endl
01184      << " scan_options     A description of various scan options: " << s.scan_options_ << vcl_endl
01185      << " mr_acq_type      The acquisition type for this scan: " << s.mr_acq_type_ << vcl_endl
01186      << " sequence_name    The name of the sequence: " << s.sequence_name_ << vcl_endl
01187      << " angio_flag       The angio flag for this sequence: " << s.angio_flag_ << vcl_endl
01188      << " slice_thickness_ Slice thickness (for voxel size): " << s.slice_thickness_ << vcl_endl
01189      << " repetition_time_ Scan repetition time: " << s.repetition_time_ << vcl_endl
01190      << " echo_time        Scan echo time: " << s.echo_time_ << vcl_endl
01191      << " inversion_time   Scan inversion time: " << s.inversion_time_ << vcl_endl
01192      << " number_of_averages The number of averages for this scan: " << s.number_of_averages_ << vcl_endl
01193      << " echo_numbers     The echo numbers for this scan: " << s.echo_numbers_ << vcl_endl
01194      << " mag_field_strength The strength of the magnetic field: " << s.mag_field_strength_ << vcl_endl
01195      << " echo_train_length The length of the echo train: " << s.echo_train_length_ << vcl_endl
01196      << " pixel_bandwidth  The bandwidth of the pixels: " << s.pixel_bandwidth_ << vcl_endl
01197      << " software_vers_   Versions of the scanner software used: " << s.software_vers_ << vcl_endl
01198      << " protocol_name    The name of the protocol used: " << s.protocol_name_ << vcl_endl
01199      << " heart_rate       The patient's heart rate: " << s.heart_rate_ << vcl_endl
01200      << " card_num_images  The cardiac number of images: " << s.card_num_images_ << vcl_endl
01201      << " trigger_window   The trigger window for this image: " << s.trigger_window_ << vcl_endl
01202      << " reconst_diameter The reconstruction diameter: " << s.reconst_diameter_ << vcl_endl
01203      << " receiving_coil_  Details of the receiving coil: " << s.receiving_coil_ << vcl_endl
01204      << " phase_enc_dir    The phase encoding direction: " << s.phase_enc_dir_ << vcl_endl
01205      << " flip_angle       The flip angle: " << s.flip_angle_ << vcl_endl
01206      << " sar              The specific absorption rate: " << s.sar_ << vcl_endl
01207      << " patient_pos      The position of the patient in the scanner: " << s.patient_pos_ << vcl_endl
01208 
01209      << "\n\nRelationship info\n"
01210      << " stud_ins_uid     The study instance unique id: " << s.stud_ins_uid_ << vcl_endl
01211      << " ser_ins_uid      The series instance unique id: " << s.ser_ins_uid_ << vcl_endl
01212      << " study_id         The id of this study: " << s.study_id_ << vcl_endl
01213      << " series_number    The number of this series: " << s.series_number_ << vcl_endl
01214      << " acquisition_number The number of the acquisition: " << s.acquisition_number_ << vcl_endl
01215      << " image_number     The number of this image instance: " << s.image_number_ << vcl_endl
01216      << " pat_orient       The orientation of the patient: " << s.pat_orient_ << vcl_endl
01217      << " image_pos        The image position relative to the patient: " << s.image_pos_[0] << '/' << s.image_pos_[1] << '/' << s.image_pos_[2] << vcl_endl
01218      << " image_orient     The image orientation relative to the patient: " << s.image_orient_[0] << '/' << s.image_orient_[1] << '/' << s.image_orient_[2] << '/' << s.image_orient_[3] << '/' << s.image_orient_[4] << '/' << s.image_orient_[5] << vcl_endl
01219      << " frame_of_ref     The frame of reference" << s.frame_of_ref_ << vcl_endl
01220      << " images_in_acq    Then number ot images in the acquisition: " << s.images_in_acq_ << vcl_endl
01221      << " pos_ref_ind      The position reference indicator: " << s.pos_ref_ind_ << vcl_endl
01222      << " slice_location   The location of the slice: " << s.slice_location_ << vcl_endl
01223 
01224      << "\n\nImage info\n"
01225      << " pix_samps        The number of samples per pixel: " << s.pix_samps_ << vcl_endl
01226      << " photo_interp     The photometric interpretation: " << s.photo_interp_ << vcl_endl
01227      << " size_x           The number of columns: " << s.size_x_ << vcl_endl
01228      << " size_y           The number of rows: " << s.size_y_ << vcl_endl
01229      << " size_z           The number of planes: " << s.size_z_ << vcl_endl
01230      << " high_bit         The bit used as the high bit: " << s.high_bit_ << vcl_endl
01231      << " small_im_pix_val The smallest image pixel value: " << s.small_im_pix_val_ << vcl_endl
01232      << " large_im_pix_val The largest image pixel value: " << s.large_im_pix_val_ << vcl_endl
01233      << " pixel_padding_val The value used for padding pixels: " << s.pixel_padding_val_ << vcl_endl
01234      << " window_centre    The value of the image window's centre: " << s.window_centre_ << vcl_endl
01235      << " window_width     The actual width of the image window: " << s.window_width_ << vcl_endl
01236 
01237      << "\n\nInfo from the tags specifically for reading the image data\n"
01238      << " spaxing_x        The pixel spacing in x: " << s.spacing_x_ << vcl_endl
01239      << " spacing_y        The pixel spacing in y: " << s.spacing_y_ << vcl_endl
01240      << " spacing_slice    The pixel spacing in z: " << s.spacing_slice_ << vcl_endl
01241      << " res_intercept    The image rescale intercept: " << s.res_intercept_ << vcl_endl
01242      << " res_slope        The image rescale slope: " << s.res_slope_ << vcl_endl
01243      << " pix_rep          The pixel representation (+/-): " << s.pix_rep_ << vcl_endl
01244      << " stored_bits      The bits stored: " << s.stored_bits_ << vcl_endl
01245      << " allocated_bits   The bits allocated: " << s.allocated_bits_ << vcl_endl;
01246 }
01247 
01248 #endif // HAS_DCMTK