]> Creatis software - gdcm.git/blob - Example/PrintFile.cxx
Add the printing od 'Orientaion' information
[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 10:27:22 $
7   Version:   $Revision: 1.59 $
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             std::cout << "PatientPosition (0x0010,0x5100)= [" 
323                       << strPatientPosition << "]" << std::endl;
324  
325      std::string strPatientOrientation = 
326                                       f->GetEntryValue(0x0020,0x0020);
327       if ( strPatientOrientation != gdcm::GDCM_UNFOUND )  
328          std::cout << "PatientOrientation (0x0020,0x0020)= [" 
329                    << strPatientOrientation << "]" << std::endl;
330
331       std::string strImageOrientationPatient = 
332                                       f->GetEntryValue(0x0020,0x0037);  
333       if ( strImageOrientationPatient != gdcm::GDCM_UNFOUND )  
334          std::cout << "ImageOrientationPatient (0x0020,0x0037)= [" 
335                    << strImageOrientationPatient << "]" << std::endl;
336
337       std::string strImageOrientationRET = 
338                                       f->GetEntryValue(0x0020,0x0035);
339       if ( strImageOrientationRET != gdcm::GDCM_UNFOUND )  
340          std::cout << "ImageOrientationRET (0x0020,0x0035)= [" 
341                    << strImageOrientationRET << "]" << std::endl;
342
343       // Let's compute 'user friendly' results about 'Orientation'
344       // ---------------------------------------------------------
345  
346       gdcm::Orientation o;
347
348       if ( strImageOrientationPatient != gdcm::GDCM_UNFOUND ||
349            strImageOrientationRET     != gdcm::GDCM_UNFOUND )
350       {
351   
352          double orient = o.TypeOrientation( f );
353          int k = (int)orient;
354          if (k < 0) 
355             k = -k + 6;
356  
357          std::cout << "TypeOrientation = " << orient << " (-> " 
358                    << tabOrientation[k] << " )" << std::endl;
359       }
360
361       std::string ori = o.GetOrientation ( f );
362       if (ori != "\\" )
363          std::cout << "Orientation [" << ori << "]" << std::endl;
364
365
366       // Display the LUT as an int array (for debugging purpose)
367       if ( f->HasLUT() && showlut )
368       {
369          uint8_t* lutrgba = fh->GetLutRGBA();
370          if ( lutrgba == 0 )
371          {
372             std::cout << "Lut RGBA (Palette Color) not built " << std::endl;
373  
374            // Nothing is written yet to get LUT Data user friendly
375            // The following is to be moved into a PixelRedaConvert method
376   
377             gdcm::SeqEntry *modLutSeq = f->GetSeqEntry(0x0028,0x3000);
378             if ( modLutSeq !=0 )
379             {
380                gdcm::SQItem *sqi= modLutSeq->GetFirstSQItem();
381                if ( !sqi )
382                {
383                std::string lutDescriptor = sqi->GetEntryValue(0x0028,0x3002);
384                   int length;   // LUT length in Bytes
385                   int deb;      // Subscript of the first Lut Value
386                   int nbits;    // Lut item size (in Bits)
387                   int nbRead;    // nb of items in LUT descriptor (must be = 3)
388
389                   nbRead = sscanf( lutDescriptor.c_str(),
390                                     "%d\\%d\\%d",
391                                      &length, &deb, &nbits );
392                   if ( nbRead != 3 )
393                   {
394                       //gdcmWarningMacro( "Wrong LUT descriptor" );
395                       std::cout << "Wrong LUT descriptor" << std::endl;
396                   }                                                  
397                   gdcm::BinEntry *b = sqi->GetBinEntry(0x0028,0x3006);
398                   if ( b != 0 )
399                   {
400                      if ( b->GetLength() != 0 )
401                      {
402                         std::cout << "---------------------------------------"
403                                << " We should never reach this point      "
404                                << std::endl;
405                         //LoadEntryBinArea(b);    //LUT Data (CTX dependent)
406                      }   
407                  }
408               }      
409             }
410             else
411                std::cout << "No LUT Data (0x0028,0x3000) found " << std::endl;
412         }
413          else
414          {
415             if ( fh->GetLutItemSize() == 8 )
416             {
417                for (int i=0;i<fh->GetLutItemNumber();i++)
418                   std::cout << i << " : \t"
419                          << (int)(lutrgba[i*4])   << " "
420                          << (int)(lutrgba[i*4+1]) << " "
421                          << (int)(lutrgba[i*4+2]) << std::endl;
422             }
423             else // LutItemSize assumed to be = 16
424             {
425                uint16_t* lutrgba16 = (uint16_t*)lutrgba;
426                for (int i=0;i<fh->GetLutItemNumber();i++)
427                   std::cout << i << " : \t"
428                          << (int)(lutrgba16[i*4])   << " "
429                          << (int)(lutrgba16[i*4+1]) << " "
430                          << (int)(lutrgba16[i*4+2]) << std::endl;
431             }
432          }
433       }
434       else if (showlut)
435       {
436          std::cout << "Try LUT Data "<< std::endl;
437          ShowLutData(f);
438       }
439
440       //if( !f->gdcm::Document::IsReadable())
441       // Try downcast to please MSVC
442      if ( !((gdcm::Document *)f)->IsReadable() )
443      {
444          std::cout <<std::endl<<fileName<<" is NOT 'gdcm parsable'"<<std::endl;
445       }
446      
447       if (f->IsReadable())
448          std::cout <<std::endl<<fileName<<" is Readable"<<std::endl;
449       else if ( f->GetSeqEntry(0x0041,0x1010) )
450       {
451          std::cout <<std::endl<<fileName<<" looks like a 'PAPYRUS image' file"
452                    <<std::endl;
453       }
454       else if ( f->GetSeqEntry(0x0004,0x1220) )
455       {
456          std::cout <<std::endl<<fileName<<" looks like a 'DICOMDIR file'"
457                    <<std::endl;
458       }
459       else 
460       {
461          std::cout <<std::endl<<fileName<<" doesn't look like an image file "
462              <<std::endl; 
463       }
464  
465       std::cout<<std::flush;
466       delete f;
467       delete fh;
468       return 0;
469    }
470    else  // ====== Deal with a Directory ======
471    {
472       std::cout << "dirName [" << dirName << "]" << std::endl;
473       gdcm::DirList dirList(dirName,1); // gets recursively the file list
474       gdcm::DirListType fileList = dirList.GetFilenames();
475       gdcm::File *f;
476       bool res;
477       for( gdcm::DirListType::iterator it  = fileList.begin();
478                                  it != fileList.end();
479                                  ++it )
480       {
481          std::cout << std::endl<<" Start processing :[" << it->c_str() << "]"
482                    << std::endl;
483          f = new gdcm::File();
484          f->SetLoadMode(loadMode);
485          f->SetFileName( it->c_str() );
486
487          for (int ri=0; ri<forceLoadNb; ri++)
488          {
489             printf("%04x,%04x\n",elemsToForceLoad[2*ri], 
490                                  elemsToForceLoad[2*ri+1]);
491             f->AddForceLoadElement((uint32_t)elemsToForceLoad[2*ri], 
492                                    (uint32_t)elemsToForceLoad[2*ri+1]); 
493          }
494          res = f->Load();
495
496          if ( !res )
497          {
498             std::cout << "Cannot process file [" << it->c_str() << "]" 
499                       << std::endl;
500             std::cout << "Either it doesn't exist, or it's read protected " 
501                       << std::endl;
502             std::cout << "or it's not a Dicom File, or its 'header' is bugged" 
503                       << std::endl;
504             std::cout << "use 'PrintFile filein=... debug' "
505                       << "to try to guess the pb"
506                       << std::endl;
507             delete f;
508             continue;
509          }
510
511          gdcm::FileHelper *fh = new gdcm::FileHelper(f);
512          fh->SetPrintLevel( level );
513
514          fh->Print();
515          gdcm::Orientation o;
516          std::string ori = o.GetOrientation ( f );
517          if (ori != gdcm::GDCM_UNFOUND )
518             std::cout << "- Orientation [" << ori << "]" << std::endl;
519
520          double d = o.TypeOrientation( f );
521          int k = (int)d;
522          if (k < 0) 
523             k = -k + 6;
524  
525          std::cout << "TypeOrientation = " << d << " (-> " 
526                    << tabOrientation[k] << std::endl;
527         
528          if (f->IsReadable())
529             std::cout <<std::endl<<it->c_str()<<" is Readable"<<std::endl;
530          else
531             std::cout <<std::endl<<it->c_str()<<" is NOT Readable"<<std::endl;
532          std::cout << "\n\n" << std::endl;
533          delete f;
534          delete fh;
535       }
536       std::cout<<std::flush;
537    }
538 }