]> Creatis software - gdcm.git/blob - Example/PrintFile.cxx
Dont print Orientations when they're empty ...
[gdcm.git] / Example / PrintFile.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: PrintFile.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/09/30 17:42:17 $
7   Version:   $Revision: 1.60 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18 #include "gdcmFile.h"
19 #include "gdcmDocument.h"
20 #include "gdcmSeqEntry.h"
21 #include "gdcmSQItem.h"
22 #include "gdcmBinEntry.h"
23
24 #include "gdcmFileHelper.h"
25 #include "gdcmDebug.h"
26 #include "gdcmDirList.h"
27 #include "gdcmGlobal.h"
28 #include "gdcmDictSet.h"
29 #include "gdcmArgMgr.h"
30 #include "gdcmOrientation.h"
31 #include <iostream>
32
33
34 void ShowLutData(gdcm::File *f);
35
36 void ShowLutData(gdcm::File *f)
37 {
38      // Nothing is written yet to get LUT Data user friendly
39      // The following is to be moved into a PixelReadConvert method
40      // Let here, waiting for a clever idea on the way to do it.
41   
42       gdcm::SeqEntry *modLutSeq = f->GetSeqEntry(0x0028,0x3000);
43       if ( modLutSeq !=0 )
44       {
45          gdcm::SQItem *sqi= modLutSeq->GetFirstSQItem();
46          if ( sqi != 0 )
47          {
48             std::string lutDescriptor = sqi->GetEntryValue(0x0028,0x3002);
49            if (   /*lutDescriptor   == GDCM_UNFOUND*/ 0 )
50            {
51               //gdcmWarningMacro( "LUT Descriptor is missing" );
52               std::cout << "LUT Descriptor is missing" << std::endl;
53               return;
54             }
55             int length;   // LUT length in Bytes
56             int deb;      // Subscript of the first Lut Value
57             int nbits;    // Lut item size (in Bits)
58
59             int nbRead;    // nb of items in LUT descriptor (must be = 3)
60
61             nbRead = sscanf( lutDescriptor.c_str(),
62                               "%d\\%d\\%d",
63                                &length, &deb, &nbits );
64            std::cout << "length " << length 
65                      << " deb " << deb 
66                      << " nbits " << nbits
67                      << std::endl;
68             if ( nbRead != 3 )
69             {
70                 //gdcmWarningMacro( "Wrong LUT descriptor" );
71                 std::cout << "Wrong LUT descriptor" << std::endl;
72             }
73             //LUT Data (CTX dependent)    
74             gdcm::BinEntry *b = sqi->GetBinEntry(0x0028,0x3006); 
75             if ( b != 0 )
76             { 
77                int BitsAllocated = f->GetBitsAllocated();
78                if ( BitsAllocated <= 8 )
79                { 
80                   int mult;
81                   if ( ( nbits == 16 ) && ( BitsAllocated == 8 ) )
82                   {
83                   // when LUT item size is different than pixel size
84                      mult = 2; // high byte must be = low byte
85                   }
86                   else
87                   {
88                   // See PS 3.3-2003 C.11.1.1.2 p 619
89                      mult = 1;
90                   }
91                   uint8_t *lut = b->GetBinArea();
92                   for( int i=0; i < length; ++i )
93                   {
94                      std::cout << i+deb << " : \t"
95                                << (int) (lut[i*mult + 1]) << std::endl;
96                   }
97                }
98                else
99                {
100                   uint16_t *lut = (uint16_t *)(b->GetBinArea());  
101                   for( int i=0; i < length; ++i )
102                   {
103                      std::cout << i+deb << " : \t"
104                                << (int) (((uint16_t *)lut)[i])
105                                << std::endl;
106                   }             
107                }
108             }  
109             else
110                std::cout << "No LUT Data BinEntry (0x0028,0x3006) found?!? " 
111                          << std::endl;
112          }
113          else
114             std::cout << "No First SQ Item within (0x0028,0x3000) ?!? " 
115                       << std::endl;      
116       }
117       else
118          std::cout << "No LUT Data SeqEntry (0x0028,0x3000) found " 
119                    << std::endl;
120    }
121
122 int main(int argc, char *argv[])
123 {
124
125    START_USAGE(usage)
126    " \n PrintFile : \n                                                        ",
127    " Display the header of a ACR-NEMA/PAPYRUS/DICOM File                      ",
128    " usage: PrintFile {filein=inputFileName|dirin=inputDirectoryName}[level=n]",
129    "                       [forceload=listOfElementsToForceLoad]              ",
130    "                       [dict= privateDirectory]                           ",
131    "                       [ { [noshadowseq] | [noshadow][noseq] } ] [debug]  ",
132    "      level = 0,1,2 : depending on the amount of details user wants to see",
133    "      listOfElementsToForceLoad : group-elem,g2-e2,... (in hexa, no space)",
134    "                                of Elements to load whatever their length ",
135    "      privateDirectory : source file full path name of Shadow Group elems ",
136    "      noshadowseq: user doesn't want to load Private Sequences            ",
137    "      noshadow   : user doesn't want to load Private groups (odd number)  ",
138    "      noseq      : user doesn't want to load Sequences                    ",
139    "      debug      : user wants to run the program in 'debug mode'          ",
140    "      showlut :user wants to display the Palette Color (as an int array)  ",
141    FINISH_USAGE
142
143    // Initialize Arguments Manager   
144    gdcm::ArgMgr *am= new gdcm::ArgMgr(argc, argv);
145   
146    if (argc == 1 || am->ArgMgrDefined("usage") )
147    {
148       am->ArgMgrUsage(usage); // Display 'usage'
149       delete am;
150       return 0;
151    }
152
153    char *fileName = am->ArgMgrGetString("filein",(char *)0);
154    char *dirName  = am->ArgMgrGetString("dirin",(char *)0);
155
156    if ( (fileName == 0 && dirName == 0)
157         ||
158         (fileName != 0 && dirName != 0) )
159    {
160        std::cout <<std::endl
161                  << "Either 'filein=' or 'dirin=' must be present;" 
162                  << std::endl << "Not both" << std::endl;
163        am->ArgMgrUsage(usage); // Display 'usage'  
164        delete am;
165        return 0;
166  }
167
168    if (am->ArgMgrDefined("debug"))
169       gdcm::Debug::DebugOn();
170  
171    int loadMode = gdcm::LD_ALL;
172    if ( am->ArgMgrDefined("noshadowseq") )
173       loadMode |= gdcm::LD_NOSHADOWSEQ;
174    else 
175    {
176    if ( am->ArgMgrDefined("noshadow") )
177          loadMode |= gdcm::LD_NOSHADOW;
178       if ( am->ArgMgrDefined("noseq") )
179          loadMode |= gdcm::LD_NOSEQ;
180    }
181
182    int level = am->ArgMgrGetInt("level", 1);
183
184    int forceLoadNb;
185    uint16_t *elemsToForceLoad 
186                            = am->ArgMgrGetXInt16Enum("forceload", &forceLoadNb);
187
188    bool showlut = ( 0 != am->ArgMgrDefined("SHOWLUT") );
189
190    bool ddict = am->ArgMgrDefined("dict") ? true : false;
191    char *dict = 0;
192
193    if (ddict)
194    {
195      dict = am->ArgMgrGetString("dict",(char *)0);
196    }
197
198    /* if unused Param we give up */
199    if ( am->ArgMgrPrintUnusedLabels() )
200    {
201       am->ArgMgrUsage(usage);
202       delete am;
203       return 0;
204    } 
205
206    delete am;  // we don't need Argument Manager any longer
207
208    // ----------- End Arguments Manager ---------
209
210    std::string tabOrientation[13] = { 
211        "Not Applicable",
212        "Axial",
213        "Coronal",
214        "Sagital",
215        "Heart Axial",
216        "Heart Coronal",
217        "Heart Sagital",
218        "Axial invert",
219        "Coronal invert",
220        "Sagital invert",
221        "Heart Axial invert",
222        "Heart Coronal invert",
223        "Heart Sagital invert"
224    };
225  
226    if (ddict)
227    {
228       gdcm::Global::GetDicts()->GetDefaultPubDict()->AddDict(dict);   
229    }
230
231    if ( fileName != 0 ) // ====== Deal with a single file ======
232    { 
233       // gdcm::File::IsReadable() is no usable here, because we deal with
234       // any kind of gdcm-Parsable *document* 
235       // not only gdcm::File (as opposed to gdcm::DicomDir)
236
237       gdcm::File *f = new gdcm::File();
238       f->SetLoadMode(loadMode);
239       f->SetFileName( fileName );
240
241       for (int ri=0; ri<forceLoadNb; ri++)
242       {
243          f->AddForceLoadElement((uint32_t)elemsToForceLoad[2*ri], 
244                                 (uint32_t)elemsToForceLoad[2*ri+1] ); 
245       }
246
247       bool res = f->Load();
248       if ( !res )
249       {
250          std::cout << "Cannot process file [" << fileName << "]" << std::endl;
251          std::cout << "Either it doesn't exist, or it's read protected " 
252                    << std::endl;
253          std::cout << "or it's not a Dicom File, or its 'header' is bugged" 
254                    << std::endl;
255          std::cout << "use 'PrintFile filein=... debug' to try to guess the pb"
256                    << std::endl;
257          delete f;
258          return 0;
259       }
260
261       gdcm::FileHelper *fh = new gdcm::FileHelper(f);
262       fh->SetPrintLevel( level );
263
264       fh->Print();
265
266       std::cout << "\n\n" << std::endl; 
267
268       std::cout <<std::endl;
269       std::cout <<" dataSize    " << fh->GetImageDataSize()    << std::endl;
270       std::cout <<" dataSizeRaw " << fh->GetImageDataRawSize() << std::endl;
271
272       int nX,nY,nZ,sPP,planarConfig;
273       std::string pixelType;
274       nX=f->GetXSize();
275       nY=f->GetYSize();
276       nZ=f->GetZSize();
277       std::cout << " DIMX=" << nX << " DIMY=" << nY << " DIMZ=" << nZ 
278                 << std::endl;
279
280       pixelType    = f->GetPixelType();
281       sPP          = f->GetSamplesPerPixel();
282       planarConfig = f->GetPlanarConfiguration();
283
284       std::cout << " pixelType= ["            << pixelType 
285                 << "] SamplesPerPixel= ["     << sPP
286                 << "] PlanarConfiguration= [" << planarConfig 
287                 << "] "<< std::endl 
288                 << " PhotometricInterpretation= [" 
289                                 << f->GetEntryValue(0x0028,0x0004)
290                 << "] "<< std::endl;
291
292       int numberOfScalarComponents=f->GetNumberOfScalarComponents();
293       std::cout << " NumberOfScalarComponents = " << numberOfScalarComponents 
294                 <<std::endl
295                 << " LUT = " << (f->HasLUT() ? "TRUE" : "FALSE")
296                 << std::endl;
297
298       if ( f->GetEntryValue(0x0002,0x0010) == gdcm::GDCM_NOTLOADED ) 
299       {
300          std::cout << "Transfer Syntax not loaded. " << std::endl
301                    << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE"
302                 << std::endl;
303          return 0;
304       }
305   
306       std::string transferSyntaxName = f->GetTransferSyntaxName();
307       std::cout << " TransferSyntaxName= [" << transferSyntaxName << "]" 
308                 << std::endl;
309       std::cout << " SwapCode= " << f->GetSwapCode() << std::endl;
310       std::cout << " ------" << std::endl;
311       //std::cout << "\n\n" << std::endl; 
312       //std::cout << "X spacing " << f->GetXSpacing() << std::endl;
313       //std::cout << "Y spacing " << f->GetYSpacing() << std::endl;
314       //std::cout << "Z spacing " << f->GetZSpacing() << std::endl;
315
316       // Lets's get and print some usefull fields about 'Orientation'
317       // ------------------------------------------------------------
318
319       std::string strPatientPosition = 
320                                       f->GetEntryValue(0x0018,0x5100);
321       if ( strPatientPosition != gdcm::GDCM_UNFOUND 
322         && strPatientPosition != "" )  
323             std::cout << "PatientPosition (0x0010,0x5100)= [" 
324                       << strPatientPosition << "]" << std::endl;
325  
326      std::string strPatientOrientation = 
327                                       f->GetEntryValue(0x0020,0x0020);
328       if ( strPatientOrientation != gdcm::GDCM_UNFOUND
329         && strPatientOrientation != "")  
330          std::cout << "PatientOrientation (0x0020,0x0020)= [" 
331                    << strPatientOrientation << "]" << std::endl;
332
333       std::string strImageOrientationPatient = 
334                                       f->GetEntryValue(0x0020,0x0037);  
335       if ( strImageOrientationPatient != gdcm::GDCM_UNFOUND
336         && strImageOrientationPatient != "" )  
337          std::cout << "ImageOrientationPatient (0x0020,0x0037)= [" 
338                    << strImageOrientationPatient << "]" << std::endl;
339
340       std::string strImageOrientationRET = 
341                                       f->GetEntryValue(0x0020,0x0035);
342       if ( strImageOrientationRET != gdcm::GDCM_UNFOUND
343         && strImageOrientationRET != "" )  
344          std::cout << "ImageOrientationRET (0x0020,0x0035)= [" 
345                    << strImageOrientationRET << "]" << std::endl;
346
347       // Let's compute 'user friendly' results about 'Orientation'
348       // ---------------------------------------------------------
349  
350       gdcm::Orientation o;
351
352       if ( strImageOrientationPatient != gdcm::GDCM_UNFOUND ||
353            strImageOrientationRET     != gdcm::GDCM_UNFOUND )
354       {
355   
356          double orient = o.TypeOrientation( f );
357          int k = (int)orient;
358          if (k < 0) 
359             k = -k + 6;
360  
361          std::cout << "TypeOrientation = " << orient << " (-> " 
362                    << tabOrientation[k] << " )" << std::endl;
363       }
364
365       std::string ori = o.GetOrientation ( f );
366       if (ori != "\\" )
367          std::cout << "Orientation [" << ori << "]" << std::endl;
368
369
370       // Display the LUT as an int array (for debugging purpose)
371       if ( f->HasLUT() && showlut )
372       {
373          uint8_t* lutrgba = fh->GetLutRGBA();
374          if ( lutrgba == 0 )
375          {
376             std::cout << "Lut RGBA (Palette Color) not built " << std::endl;
377  
378            // Nothing is written yet to get LUT Data user friendly
379            // The following is to be moved into a PixelRedaConvert method
380   
381             gdcm::SeqEntry *modLutSeq = f->GetSeqEntry(0x0028,0x3000);
382             if ( modLutSeq !=0 )
383             {
384                gdcm::SQItem *sqi= modLutSeq->GetFirstSQItem();
385                if ( !sqi )
386                {
387                std::string lutDescriptor = sqi->GetEntryValue(0x0028,0x3002);
388                   int length;   // LUT length in Bytes
389                   int deb;      // Subscript of the first Lut Value
390                   int nbits;    // Lut item size (in Bits)
391                   int nbRead;   // nb of items in LUT descriptor (must be = 3)
392
393                   nbRead = sscanf( lutDescriptor.c_str(),
394                                     "%d\\%d\\%d",
395                                      &length, &deb, &nbits );
396                   if ( nbRead != 3 )
397                   {
398                       //gdcmWarningMacro( "Wrong LUT descriptor" );
399                       std::cout << "Wrong LUT descriptor" << std::endl;
400                   }                                                  
401                   gdcm::BinEntry *b = sqi->GetBinEntry(0x0028,0x3006);
402                   if ( b != 0 )
403                   {
404                      if ( b->GetLength() != 0 )
405                      {
406                         std::cout << "---------------------------------------"
407                                << " We should never reach this point      "
408                                << std::endl;
409                         //LoadEntryBinArea(b);    //LUT Data (CTX dependent)
410                      }   
411                  }
412               }      
413             }
414             else
415                std::cout << "No LUT Data (0x0028,0x3000) found " << std::endl;
416         }
417          else
418          {
419             if ( fh->GetLutItemSize() == 8 )
420             {
421                for (int i=0;i<fh->GetLutItemNumber();i++)
422                   std::cout << i << " : \t"
423                          << (int)(lutrgba[i*4])   << " "
424                          << (int)(lutrgba[i*4+1]) << " "
425                          << (int)(lutrgba[i*4+2]) << std::endl;
426             }
427             else // LutItemSize assumed to be = 16
428             {
429                uint16_t* lutrgba16 = (uint16_t*)lutrgba;
430                for (int i=0;i<fh->GetLutItemNumber();i++)
431                   std::cout << i << " : \t"
432                          << (int)(lutrgba16[i*4])   << " "
433                          << (int)(lutrgba16[i*4+1]) << " "
434                          << (int)(lutrgba16[i*4+2]) << std::endl;
435             }
436          }
437       }
438       else if (showlut)
439       {
440          std::cout << "Try LUT Data "<< std::endl;
441          ShowLutData(f);
442       }
443
444       //if( !f->gdcm::Document::IsReadable())
445       // Try downcast to please MSVC
446      if ( !((gdcm::Document *)f)->IsReadable() )
447      {
448          std::cout <<std::endl<<fileName<<" is NOT 'gdcm parsable'"<<std::endl;
449       }
450      
451       if (f->IsReadable())
452          std::cout <<std::endl<<fileName<<" is Readable"<<std::endl;
453       else if ( f->GetSeqEntry(0x0041,0x1010) )
454       {
455          std::cout <<std::endl<<fileName<<" looks like a 'PAPYRUS image' file"
456                    <<std::endl;
457       }
458       else if ( f->GetSeqEntry(0x0004,0x1220) )
459       {
460          std::cout <<std::endl<<fileName<<" looks like a 'DICOMDIR file'"
461                    <<std::endl;
462       }
463       else 
464       {
465          std::cout <<std::endl<<fileName<<" doesn't look like an image file "
466              <<std::endl; 
467       }
468  
469       std::cout<<std::flush;
470       delete f;
471       delete fh;
472       return 0;
473    }
474    else  // ====== Deal with a Directory ======
475    {
476       std::cout << "dirName [" << dirName << "]" << std::endl;
477       gdcm::DirList dirList(dirName,1); // gets recursively the file list
478       gdcm::DirListType fileList = dirList.GetFilenames();
479       gdcm::File *f;
480       bool res;
481       for( gdcm::DirListType::iterator it  = fileList.begin();
482                                  it != fileList.end();
483                                  ++it )
484       {
485          std::cout << std::endl<<" Start processing :[" << it->c_str() << "]"
486                    << std::endl;
487          f = new gdcm::File();
488          f->SetLoadMode(loadMode);
489          f->SetFileName( it->c_str() );
490
491          for (int ri=0; ri<forceLoadNb; ri++)
492          {
493             printf("%04x,%04x\n",elemsToForceLoad[2*ri], 
494                                  elemsToForceLoad[2*ri+1]);
495             f->AddForceLoadElement((uint32_t)elemsToForceLoad[2*ri], 
496                                    (uint32_t)elemsToForceLoad[2*ri+1]); 
497          }
498          res = f->Load();
499
500          if ( !res )
501          {
502             std::cout << "Cannot process file [" << it->c_str() << "]" 
503                       << std::endl;
504             std::cout << "Either it doesn't exist, or it's read protected " 
505                       << std::endl;
506             std::cout << "or it's not a Dicom File, or its 'header' is bugged" 
507                       << std::endl;
508             std::cout << "use 'PrintFile filein=... debug' "
509                       << "to try to guess the pb"
510                       << std::endl;
511             delete f;
512             continue;
513          }
514
515          gdcm::FileHelper *fh = new gdcm::FileHelper(f);
516          fh->SetPrintLevel( level );
517
518          fh->Print();
519          gdcm::Orientation o;
520          std::string ori = o.GetOrientation ( f );
521          if (ori != gdcm::GDCM_UNFOUND )
522             std::cout << "- Orientation [" << ori << "]" << std::endl;
523
524          double d = o.TypeOrientation( f );
525          int k = (int)d;
526          if (k < 0) 
527             k = -k + 6;
528  
529          std::cout << "TypeOrientation = " << d << " (-> " 
530                    << tabOrientation[k] << std::endl;
531         
532          if (f->IsReadable())
533             std::cout <<std::endl<<it->c_str()<<" is Readable"<<std::endl;
534          else
535             std::cout <<std::endl<<it->c_str()<<" is NOT Readable"<<std::endl;
536          std::cout << "\n\n" << std::endl;
537          delete f;
538          delete fh;
539       }
540       std::cout<<std::flush;
541    }
542 }