]> Creatis software - gdcm.git/blob - Example/ToInTag.cxx
Black outing the burnt-in number of some MRI images
[gdcm.git] / Example / ToInTag.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: ToInTag.cxx,v $
5   Language:  C++
6   Date:      $Date: 2006/06/02 05:46:44 $
7   Version:   $Revision: 1.3 $
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 "gdcmDocEntry.h"
19 #include "gdcmDicomDir.h"
20 #include "gdcmDicomDirPatient.h"
21 #include "gdcmFile.h"
22 #include "gdcmFileHelper.h"
23 #include "gdcmDirList.h"
24 #include "gdcmDebug.h"
25 #include "gdcmArgMgr.h"
26 #include "gdcmUtil.h"
27 #include "gdcmSerieHelper.h"
28
29 #include <iostream>
30
31 /**
32   * \brief   
33   *          - explores recursively the given directory
34   *          - keeps the requested series
35   *          - orders the gdcm-readable found Files
36   *            according to their Patient/Study/Serie/Image characteristics
37   *          - fills a single level Directory with *all* the files,
38   *            converted into a Brucker-like Dicom, Intags compliant
39   */  
40
41 typedef std::map<std::string, gdcm::File*> SortedFiles;
42
43 int main(int argc, char *argv[]) 
44 {
45    START_USAGE(usage)
46    " \n ToInTag :\n                                                           ",
47    " - explores recursively the given directory,                              ",
48    " - keeps the requested series/ drops the unrequested series               ",
49    " - orders the gdcm-readable found Files according to their                ",
50    "           (0x0010, 0x0010) Patient's Name                                ",
51    "           (0x0020, 0x000e) Series Instance UID                           ",
52    "           (0x0020, 0x0032) Image Position (Patient)                      ",
53    "           (0x0018, 0x1060) Trigger Time                                  ",
54    "           (0x0018, 0x1312) In-plane Phase Encoding Direction             ",
55    " - fills a single level (*) Directory with *all* the files,               ",
56    "           converted into a Brucker-like Dicom, InTags compliant          ",
57    "   (*) actually : creates as many directories as Patients                 ",
58    "                  -that shouldn't appear, but being carefull is better ! -",
59    " or                                                                       ",
60    " - fills a tree-like structure of directories as :                        ",
61    "        - Patient                                                         ",
62    "        -- Serie                                                          ",
63    "        --- Position                                                      ",
64    "            Images are (sorted by Trigger Time /                          ",
65    "                     Encoding Direction (Row, Column)                     ",
66    "      use :                                                               ",
67    "           0x0021, 0x1020 : 'SLICE INDEX'                                 ",
68    "           0x0021, 0x1040 : 'FRAME INDEX'                                 ",
69    "           0x0020, 0x0012 : 'SESSION INDEX'  (Acquisition Number)         ",
70    " usage:                                                                   ",
71    " PhilipsToBrucker dirin=rootDirectoryName                                 ",
72    "                  dirout=outputDirectoryName                              ",
73    "                  {  [keep= list of seriesNumber to process]              ",
74    "                   | [drop= list of seriesNumber to ignore] }             ",
75    "                  [taggrid] [skel]                                        ",
76    "                  [input = {ACR|DCM}]                                     ", 
77    "                  [extent=image suffix (.IMA, .NEMA, .DCM, ...)]          ",
78    "                  [listonly] [split]                                      ",
79    "                  [noshadowseq][noshadow][noseq] [verbose] [debug]        ",
80    "                                                                          ",
81    " dirout : will be created if doesn't exist                                ",
82    " keep : if user wants to process a limited number of series               ",
83    "            he gives the list of 'SeriesNumber' (tag 0020|0011)           ",
84    " drop : if user wants to ignore a limited number of series                ",
85    "            he gives the list of 'SeriesNumber' (tag 0020|0011)           ",   
86    "        SeriesNumber are short enough to be human readable                ",
87    "        e.g : 1030,1035,1043                                              ", 
88    " taggrid : user knows all the images are 'grid' -ie : not 'col', not 'raw'",
89    " extent : DO NOT forget the leading '.' !                                 ",
90    " skel: name skeleton eg : patName_1.nema -> skel=patName_                 ",
91    " split: creates a tree-like structure of directories as :                 ",
92    "        - Patient                                                         ",
93    "        -- Serie                                                          ",
94    "        --- Position                                                      ",
95    "            Images are (sorted by Trigger Time /                          ",
96    "                     Encoding Direction (Row, Column)                     ",
97    " noshadowseq: user doesn't want to load Private Sequences                 ",
98    " noshadow : user doesn't want to load Private groups (odd number)         ",
99    " noseq    : user doesn't want to load Sequences                           ",
100    " verbose  : user wants to run the program in 'verbose mode'               ",
101    " debug    : *developer*  wants to run the program in 'debug mode'         ",
102    FINISH_USAGE
103
104    // ----- Initialize Arguments Manager ------
105       
106    gdcm::ArgMgr *am = new gdcm::ArgMgr(argc, argv);
107   
108    if (argc == 1 || am->ArgMgrDefined("usage")) 
109    {
110       am->ArgMgrUsage(usage); // Display 'usage'
111       delete am;
112       return 0;
113    }
114
115    const char *dirNamein;   
116    dirNamein  = am->ArgMgrGetString("dirin","."); 
117
118    const char *dirNameout;   
119    dirNameout  = am->ArgMgrGetString("dirout",".");  
120    
121    int loadMode = gdcm::LD_ALL;
122    if ( am->ArgMgrDefined("noshadowseq") )
123       loadMode |= gdcm::LD_NOSHADOWSEQ;
124    else 
125    {
126    if ( am->ArgMgrDefined("noshadow") )
127          loadMode |= gdcm::LD_NOSHADOW;
128       if ( am->ArgMgrDefined("noseq") )
129          loadMode |= gdcm::LD_NOSEQ;
130    }
131
132    if (am->ArgMgrDefined("debug"))
133       gdcm::Debug::DebugOn();
134       
135    int verbose  = am->ArgMgrDefined("verbose");
136    int split    = am->ArgMgrDefined("split");
137    int listonly = am->ArgMgrDefined("listonly");
138          
139    int nbSeriesToKeep;
140    int *seriesToKeep = am->ArgMgrGetListOfInt("keep", &nbSeriesToKeep);
141    int nbSeriesToDrop;
142    int *seriesToDrop = am->ArgMgrGetListOfInt("drop", &nbSeriesToDrop);
143  
144    if ( nbSeriesToKeep!=0 && nbSeriesToDrop!=0)
145    {
146       std::cout << "KEEP and DROP are mutually exclusive !" << std::endl;
147       delete am;
148       return 0;         
149    }
150    
151    int taggrid = am->ArgMgrDefined("taggrid");
152    
153    int hasSkel = am->ArgMgrDefined("skel");
154    const char *skel;
155    if (hasSkel)
156       skel = am->ArgMgrGetString("skel");   
157       
158    const char *extent  = am->ArgMgrGetString("extent",".DCM");
159    
160    // if unused Param we give up
161    if ( am->ArgMgrPrintUnusedLabels() )
162    { 
163       am->ArgMgrUsage(usage);
164       delete am;
165       return 0;
166    }
167    delete am;  // we don't need Argument Manager any longer
168
169    // ----- Begin Processing -----
170    
171    if ( ! gdcm::DirList::IsDirectory(dirNamein) )
172    {
173       std::cout << "KO : [" << dirNamein << "] is not a Directory." << std::endl;
174       return 0;
175
176    }
177    else
178    {
179       std::cout << "OK : [" << dirNamein << "] is a Directory." << std::endl;
180    }
181
182    std::string systemCommand;
183    
184    std::cout << "Check for output directory :[" << dirNameout << "]."
185              <<std::endl;
186    if ( ! gdcm::DirList::IsDirectory(dirNameout) )    // dirout not found
187    {
188       std::string strDirNameout(dirNameout);          // to please gcc 4
189       systemCommand = "mkdir " +strDirNameout;        // create it!
190       if (verbose)
191          std::cout << systemCommand << std::endl;
192       system (systemCommand.c_str());
193       if ( ! gdcm::DirList::IsDirectory(dirNameout) ) // be sure it worked
194       {
195           std::cout << "KO : not a dir : [" << dirNameout << "] (creation failure ?)" << std::endl;
196       return 0;
197
198       }
199       else
200       {
201         std::cout << "Directory [" << dirNameout << "] created." << std::endl;
202       }
203    }
204    else
205    {
206        std::cout << "Output Directory [" << dirNameout << "] already exists; Used as is." << std::endl;
207    }
208     
209    std::string strDirNamein(dirNamein);
210    gdcm::DirList dirList(strDirNamein, true); // get recursively the list of files
211    
212    if (listonly)
213    {
214       std::cout << "------------List of found files ------------" << std::endl;
215       dirList.Print();
216    }
217    
218    gdcm::DirListType fileNames;
219    fileNames = dirList.GetFilenames();
220    gdcm::SerieHelper *s;              // Needed only to may use SerieHelper::AddSeriesDetail()
221    s = gdcm::SerieHelper::New();
222
223    std::string token = "%%%"; // Hope it's enough!
224 /*       
225    std::cout << "---------------Print Serie--------------" << std::endl; 
226    s->SetDirectory(dirNamein, true); // true : recursive exploration 
227    s->SetUseSeriesDetails(true);  
228    s->AddSeriesDetail(0x0018, 0x1312);   
229    s->Print();
230 */
231   
232    gdcm::File *f;
233    gdcm::FileHelper *fh;
234    std::vector<std::string> tokens;
235    std::vector<std::string> tokensForFileName;
236 /*   
237    std::cout << "---------------Print Unique Series identifiers---------"  
238              << std::endl;     
239    std::string uniqueSeriesIdentifier;
240  
241    for (gdcm::DirListType::iterator it) = fileNames.begin();  
242                                     it != fileNames.end();
243                                   ++it)
244    {
245       std::cout << "File Name : " << *it << std::endl;
246       f = gdcm::File::New();
247       f->SetLoadMode(gdcm::LD_ALL);
248       f->SetFileName( *it );
249       f->Load();
250         
251       uniqueSeriesIdentifier=s->CreateUniqueSeriesIdentifier(f);
252       std::cout << "                           [" <<
253                uniqueSeriesIdentifier  << "]" << std::endl;       
254       f->Delete();
255    }
256 */
257    
258    if (verbose)
259       std::cout << "------------------Print Break levels-----------------" << std::endl;
260
261    std::string userFileIdentifier; 
262    SortedFiles sf;
263
264    s->AddSeriesDetail(0x0010, 0x0010, false); // Patient's Name
265    s->AddSeriesDetail(0x0020, 0x000e, false); // Series Instance UID
266    s->AddSeriesDetail(0x0020, 0x0032, false); // Image Position (Patient)     
267    s->AddSeriesDetail(0x0018, 0x1060, true);  // Trigger Time (true: convert to keep numerical order)
268    s->AddSeriesDetail(0x0018, 0x1312, false); // In-plane Phase Encoding Direction 
269
270    uint8_t *imageData;
271          
272    for (gdcm::DirListType::iterator it = fileNames.begin();  
273                                     it != fileNames.end();
274                                   ++it)
275    {
276       f = gdcm::File::New();
277       f->SetLoadMode(loadMode);
278       f->SetFileName( *it );
279       f->Load();
280       
281
282       std::string strSeriesNumber;
283       int seriesNumber;
284       int j;
285
286       // keep only requested Series      
287       bool keep = false;
288       if (nbSeriesToKeep != 0)
289       {     
290          strSeriesNumber = f->GetEntryString(0x0020, 0x0011 );
291          seriesNumber = atoi( strSeriesNumber.c_str() );
292          for (j=0;j<nbSeriesToKeep; j++)
293          {
294             if(seriesNumber == seriesToKeep[j])
295             {
296                keep = true;
297                break;
298             }
299          }
300          if ( !keep)
301          {
302             f->Delete();
303             continue;
304          } 
305       }
306       // drop all unrequested Series
307       bool drop = false;
308       if (nbSeriesToDrop != 0)
309       {     
310          strSeriesNumber = f->GetEntryString(0x0020, 0x0011 );
311          seriesNumber = atoi( strSeriesNumber.c_str() );
312          for (j=0;j<nbSeriesToDrop; j++)
313          {
314             if(seriesNumber == seriesToDrop[j])
315             { 
316                drop = true;
317                break;
318             }
319         }
320         if (drop)
321         {
322            f->Delete();
323            continue;
324         }
325       }      
326
327       userFileIdentifier=s->CreateUserDefinedFileIdentifier(f); 
328       tokens.clear();
329       gdcm::Util::Tokenize (userFileIdentifier, tokens, token); 
330    
331       int imageNum; // Within FileName
332       char newName[1024];
333       
334       if ( tokens[3] == "gdcmUnfound")  // sometimes Trigger Time is not found. CreateUserDefinedFileIdentifier is not aware of the pb.
335       {
336          ///this is a trick to build up a lexicographical compliant name :
337          ///     eg : fich001.ima vs fich100.ima as opposed to fich1.ima vs fich100.ima
338          std::string name = gdcm::Util::GetName( *it );
339          if (hasSkel)
340          {
341             gdcm::Util::Tokenize (name, tokensForFileName, skel);
342             imageNum = atoi ( tokensForFileName[0].c_str() );
343             // probabely we could write something much more complicated using C++ !
344             sprintf (newName, "%s%06d%s", skel, imageNum, extent);
345             tokens[3] = newName;
346             tokensForFileName.clear();    
347          }
348          else
349             tokens[3] = name;
350  
351  
352          userFileIdentifier = tokens[0] + token + tokens[1] + token + tokens[2] + token 
353                     + tokens[3] + token + tokens[4] + token;
354       }   
355       if (verbose) 
356          std::cout << "[" << userFileIdentifier  << "]" << std::endl;
357                
358       // storing in a map ensures automatic sorting !      
359       sf[userFileIdentifier] = f;
360    }
361       
362    std::string fullFilename, lastFilename;
363    std::string previousPatientName, currentPatientName;
364    std::string previousSerieInstanceUID, currentSerieInstanceUID;
365    std::string previousImagePosition, currentImagePosition;
366    std::string previousPhaseEncodingDirection, currentPhaseEncodingDirection;
367    std::string previousTriggerTime, currentTriggerTime;
368       
369    std::string writeDir, currentWriteDir;
370    std::string currentPatientWriteDir, currentSerieWriteDir, 
371                currentPositionWriteDir, currentPhaseEncodingDirectionWriteDir;
372
373    std::string fullWriteFilename;
374    std::string strExtent(extent); 
375            
376    writeDir = gdcm::Util::NormalizePath(dirNameout);     
377    SortedFiles::iterator it2;
378  
379    previousPatientName            = "";
380    previousSerieInstanceUID       = "";   
381    previousImagePosition          = "";
382    previousPhaseEncodingDirection = "";
383    previousTriggerTime            = "";
384    
385    int sliceIndex = 0; // Is incremented *at the beginning* of processing
386    int frameIndex = 1;
387    int flag       = 0;
388        
389    gdcm::File *currentFile;
390      
391    for (it2 = sf.begin() ; it2 != sf.end(); ++it2)
392    {  
393       currentFile = it2->second;
394        
395       fullFilename =  currentFile->GetFileName();
396       lastFilename =  gdcm::Util::GetName( fullFilename ); 
397       std::cout << "Rewrite [" <<lastFilename << "]" << std::endl;
398      
399       tokens.clear();
400       gdcm::Util::Tokenize (it2->first, tokens, token);
401       
402       currentPatientName            = tokens[0];
403       currentSerieInstanceUID       = tokens[1];
404       currentImagePosition          = tokens[2];
405       currentTriggerTime            = tokens[3];
406       currentPhaseEncodingDirection = tokens[4]; 
407
408       if ( currentImagePosition[0] == '-')
409           currentImagePosition[0] = 'M';
410       if ( currentImagePosition[0] == '+')
411           currentImagePosition[0] = 'P'; 
412       
413       if (previousPatientName != currentPatientName)
414       {
415          previousPatientName = currentPatientName;
416          if (verbose)   
417             std::cout << "==== new Patient  [" << currentPatientName  << "]" << std::endl;
418     
419          previousPatientName            = currentPatientName;
420          previousSerieInstanceUID       = ""; //currentSerieInstanceUID;
421          previousImagePosition          = ""; //currentImagePosition;
422          previousTriggerTime            = "";
423          previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
424   
425          currentPatientWriteDir = writeDir + currentPatientName;
426          //if ( ! gdcm::DirList::IsDirectory(currentPatientWriteDir) )
427            {
428               systemCommand   = "mkdir " + currentPatientWriteDir;
429               if (verbose)
430                  std::cout << systemCommand << std::endl;
431               system ( systemCommand.c_str() );
432          }
433       }
434
435       if (previousSerieInstanceUID != currentSerieInstanceUID)
436       {        
437          if (verbose)   
438             std::cout << "==== === new Serie [" << currentSerieInstanceUID << "]"
439                       << std::endl;
440          if (split)
441          {
442              currentSerieWriteDir  = currentPatientWriteDir + gdcm::GDCM_FILESEPARATOR
443                              + currentSerieInstanceUID;
444              systemCommand   = "mkdir " + currentSerieWriteDir;  
445              system (systemCommand.c_str());
446          }
447          previousSerieInstanceUID       = currentSerieInstanceUID;
448          previousImagePosition          = ""; //currentImagePosition;
449          previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
450       }
451
452       if (previousImagePosition != currentImagePosition)
453       {
454          frameIndex = 1;
455          flag = 0;        
456          if (verbose)   
457             std::cout << "=== === === new Position [" << currentImagePosition  << "]"
458                       << std::endl;
459          if (split)
460          {
461              currentPositionWriteDir  = currentSerieWriteDir + gdcm::GDCM_FILESEPARATOR
462                              + currentImagePosition;
463              systemCommand   = "mkdir " + currentPositionWriteDir;     
464              system (systemCommand.c_str()); 
465          }
466          previousImagePosition          = currentImagePosition;
467          previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
468          if (split)
469             sliceIndex = 1; // only *one* slice in a given directory
470          else
471             sliceIndex += 1;
472       }      
473
474 // We don't split on Row/Column!
475 /*
476       if (previousPhaseEncodingDirection != currentPhaseEncodingDirection)
477       {        
478          if (verbose)   
479             std::cout << "==== === === === new PhaseEncodingDirection [" 
480                       << currentPhaseEncodingDirection  << "]" << std::endl;
481       
482          if (split)
483          {
484              currentPhaseEncodingDirectionWriteDir  = currentPositionWriteDir 
485                              + gdcm::GDCM_FILESEPARATOR
486                              + currentPhaseEncodingDirection;
487              systemCommand   = "mkdir " + currentPhaseEncodingDirectionWriteDir;     
488              system (systemCommand.c_str());     
489          }      
490     
491          previousPhaseEncodingDirection = currentPhaseEncodingDirection;
492       } 
493 */    
494       
495       if (verbose)
496          std::cout << "--- --- --- --- --- " << (it2->second)->GetFileName() 
497                    << std::endl;
498    
499       if ( gdcm::Debug::GetDebugFlag())
500          std::cout << "--- --- --- --- --- " << it2->first << "  " 
501                    << (it2->second)->GetFileName() << " " 
502                    << gdcm::Util::GetName( fullFilename ) << std::endl;           
503       
504       // Transform the image to be 'Brucker-Like'
505       // ----------------------------------------   
506     
507       // Deal with 0x0019, 0x1000 : 'FOV'
508       int nX = currentFile->GetXSize();
509       int nY = currentFile->GetYSize();
510       float pxSzX = currentFile->GetXSpacing();
511       float pxSzY = currentFile->GetYSpacing();
512       char fov[64];
513       sprintf(fov, "%f\\%f",nX*pxSzX, nY*pxSzY);
514       if (currentFile->IsVRCoherent(0x0019) == 1 )
515          currentFile->InsertEntryString(fov, 0x0019, 0x1000, "  ");
516       else     
517          currentFile->InsertEntryString(fov, 0x0019, 0x1000, "DS");
518
519      
520       // Deal with 0x0020, 0x0012 : 'SESSION INDEX'  (Acquisition Number)
521       std::string chSessionIndex;
522       // CLEANME
523       if (taggrid) 
524          chSessionIndex = "1";
525       else
526       {
527          if (currentPhaseEncodingDirection == "COL" || currentPhaseEncodingDirection == "COL " || currentPhaseEncodingDirection == " COL")
528             chSessionIndex = "1";
529          else if (currentPhaseEncodingDirection == "ROW" || currentPhaseEncodingDirection == "ROW "|| currentPhaseEncodingDirection == " ROW")
530             chSessionIndex = "2"; 
531          else
532          {
533             std::cout << "====================== PhaseEncodingDirection "
534                       << " neither COL nor ROW (?!?) : [ "
535                       << currentPhaseEncodingDirection << "]" << std::endl;
536             chSessionIndex = "1";
537          }
538       }
539        if (currentFile->IsVRCoherent(0x0020) == 1 )     
540          currentFile->InsertEntryString(chSessionIndex, 0x0020, 0x0012, "  ");
541        else
542          currentFile->InsertEntryString(chSessionIndex, 0x0020, 0x0012, "IS");
543  
544       // Deal with  0x0021, 0x1020 : 'SLICE INDEX'
545       char chSliceIndex[5];
546       sprintf(chSliceIndex, "%04d", sliceIndex);
547       std::string strChSliceIndex(chSliceIndex);
548        
549       // Deal with  0x0021, 0x1040 : 'FRAME INDEX' 
550       char chFrameIndex[5];
551       sprintf(chFrameIndex, "%04d", frameIndex);
552
553       std::string stringVR;       
554       if (currentFile->IsVRCoherent(0x0021) == 1 )
555          stringVR = "  ";
556       else
557         stringVR = "IS";
558   
559       currentFile->InsertEntryString(strChSliceIndex, 0x0021, 0x1020, stringVR);
560       currentFile->InsertEntryString(chFrameIndex,    0x0021, 0x1040, stringVR); 
561  
562  
563       std::string strImagePositionPatient    = currentFile->GetEntryString(0x0020, 0x0032 );
564       if (strImagePositionPatient == gdcm::GDCM_UNFOUND)
565          currentFile->InsertEntryString(currentFile->GetEntryString(0x0020, 0x0030), 0x0020, 0x0032, "DS" );  
566       
567       std::string strImageOrientationPatient = f->GetEntryString(0x0020, 0x0037 );
568       if (strImageOrientationPatient == gdcm::GDCM_UNFOUND)
569          currentFile->InsertEntryString(currentFile->GetEntryString(0x0020, 0x0035), 0x0020, 0x0037, "DS" );       
570                 
571       if (taggrid)
572          frameIndex++;
573       else     
574       {     
575          if (flag == 0)
576          {       
577             flag = 1;
578          }
579          else
580          {
581             frameIndex++;
582             flag = 0;
583          }
584       } 
585                  
586       if (split)
587       
588          //fullWriteFilename = currentPhaseEncodingDirectionWriteDir + gdcm::GDCM_FILESEPARATOR 
589          //                                + lastFilename + strExtent;      
590          fullWriteFilename = currentPositionWriteDir + gdcm::GDCM_FILESEPARATOR 
591                                          + lastFilename + strExtent; 
592       else
593          fullWriteFilename = currentPatientWriteDir + gdcm::GDCM_FILESEPARATOR 
594                                          + lastFilename + strExtent; 
595       
596       /*           
597       systemCommand  = "cp " + fullFilename + " " + fullWriteFilename;
598       std::cout << systemCommand << std::endl;
599       system (  systemCommand.c_str() );
600       */
601             
602       // Load the pixels in RAM.    
603       
604       fh = gdcm::FileHelper::New(currentFile);     
605       uint8_t *imageData = fh->GetImageDataRaw(); // Don't convert (Gray Pixels + LUT) into (RGB pixels) ?!?
606       fh->SetWriteTypeToDcmExplVR();
607       // We didn't modify pixels -> keep unchanged the following :
608       // 'Media Storage SOP Class UID' (0x0002,0x0002)
609       // 'SOP Class UID'               (0x0008,0x0016)
610       // 'Image Type'                  (0x0008,0x0008)
611       // 'Conversion Type'             (0x0008,0x0064)
612       
613       // Put to Black the burnt-in number.
614       nX = currentFile->GetXSize();
615       nY = currentFile->GetYSize();
616       for(int y=nY-15; y<nY; y++)
617          for(int x=nX/3; x<nX/2+50; x++)
618            imageData[ y*nX*2 + x ] = 0;   
619         
620       fh->SetContentType(gdcm::UNMODIFIED_PIXELS_IMAGE);
621       if (!fh->Write(fullWriteFilename))
622       {
623          std::cout << "Fail to write :[" << fullWriteFilename << "]"
624                    << std::endl;
625       } 
626       fh->Delete();                
627    }
628    return 0;
629  }