]> Creatis software - gdcm.git/blob - Example/ReWrite.cxx
Allow user to ask for MONOCHROME1 (0 = white) writting.
[gdcm.git] / Example / ReWrite.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: ReWrite.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/07/04 10:43:19 $
7   Version:   $Revision: 1.27 $
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 "gdcmFileHelper.h"
20 #include "gdcmDebug.h"
21
22 #include "gdcmArgMgr.h"
23
24 #include <string.h> // for memcpy
25 #include <iostream>
26
27 int main(int argc, char *argv[])
28 {
29    START_USAGE(usage)
30    " \n ReWrite :\n",
31    " Re write a full gdcm-readable Dicom image                              ",
32    "     (usefull when the file header is not very straight).               ",
33    "                                                                        ",
34    " usage: ReWrite filein=inputFileName fileout=outputFileName             ", 
35    "       [mode=write mode] [monochrome1] [noshadow] [noseq][debug]        ",
36    "  --> The following line to 'rubout' a burnt-in Patient name            ",
37    "       [rubout=xBegin,xEnd,yBegin,yEnd [ruboutvalue=n (<255)] ]         ",
38    "  --> The 2 following lines, to extract a sub image within some frames  ",
39    "       [ROI=xBegin,xEnd,yBegin,yEnd]                                    ",
40    "       [firstframe=beg] [lastframe=end]                                 ", 
41    "                                                                        ",
42    "        mode = a (ACR), x (Explicit VR Dicom), r (RAW : only pixels)    ",
43    "        monochrome1 = user wants MONOCHROME1 photom. interp. (0=white)  ",
44    "        noshadowseq: user doesn't want to load Private Sequences        ",
45    "        noshadow : user doesn't want to load Private groups (odd number)",
46    "        noseq    : user doesn't want to load Sequences                  ",
47    "        rgb      : user wants to transform LUT (if any) to RGB pixels   ",
48    "        warning  : developper wants to run the program in 'warning mode'",
49    "        debug    : developper wants to run the program in 'debug mode'  ",
50    FINISH_USAGE
51
52    // ----- Initialize Arguments Manager ------   
53    GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
54   
55    if (argc == 1 || am->ArgMgrDefined("usage")) 
56    {
57       am->ArgMgrUsage(usage); // Display 'usage'
58       delete am;
59       return 0;
60    }
61    char *fileName = am->ArgMgrWantString("filein",usage);
62    if ( fileName == NULL )
63    {
64       std::cout << "'filein= ...' is mandatory" << std::endl;
65       delete am;
66       return 0;
67    }
68
69    char *outputFileName = am->ArgMgrWantString("fileout",usage);
70    if ( outputFileName == NULL )
71    {
72       std::cout << "'fileout= ...' is mandatory" << std::endl;
73       delete am;
74       return 0;
75    }
76
77    const char *mode = am->ArgMgrGetString("mode","X");
78
79    int loadMode = GDCM_NAME_SPACE::LD_ALL;
80    if ( am->ArgMgrDefined("noshadowseq") )
81       loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
82    else 
83    {
84    if ( am->ArgMgrDefined("noshadow") )
85          loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
86       if ( am->ArgMgrDefined("noseq") )
87          loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
88    }
89
90    bool rgb = ( 0 != am->ArgMgrDefined("RGB") );
91
92    bool monochrome1 = ( 0 != am->ArgMgrDefined("monochrome1") );
93    
94    if (am->ArgMgrDefined("debug"))
95       GDCM_NAME_SPACE::Debug::DebugOn();
96
97    if (am->ArgMgrDefined("warning"))
98       GDCM_NAME_SPACE::Debug::WarningOn();
99             
100    bool fail = false;
101    int *boundVal;
102    int ruboutVal;
103    bool rubout = false; 
104    if (am->ArgMgrDefined("rubout"))
105    {
106       int nbBound;
107       boundVal = am->ArgMgrGetListOfInt("rubout", &nbBound);
108
109       if (nbBound !=4)
110       {
111          std::cout << "Illegal number of 'rubout' boundary values (expected : 4, found:" 
112                    << nbBound << "); 'rubout' ignored" << std::endl;
113          fail = true;
114       }
115             
116       ruboutVal = am->ArgMgrGetInt("ruboutvalue", 0);
117       rubout = true;   
118    }
119
120    int *roiBoundVal;
121    bool roi = false; 
122    if (am->ArgMgrDefined("roi"))
123    {
124       int nbRoiBound;
125       roiBoundVal = am->ArgMgrGetListOfInt("roi", &nbRoiBound);
126
127       if (nbRoiBound !=4)
128       {
129         std::cout << "Illegal number of 'ROI' boundary values (expected : 4, found:" 
130                   << nbRoiBound << "); 'ROI' ignored" << std::endl;
131         fail = true;
132       }
133       else
134         roi = true;   
135    }
136   
137    int beg = am->ArgMgrGetInt("firstFrame",-1);
138    int end = am->ArgMgrGetInt("lastFrame",-1);
139  
140    // if unused Params we give up
141    if ( am->ArgMgrPrintUnusedLabels() )
142    { 
143       am->ArgMgrUsage(usage);
144       delete am;
145       return 0;
146    }
147
148    delete am;  // we don't need Argument Manager any longer
149
150    // ----------- End Arguments Manager ---------
151
152    GDCM_NAME_SPACE::File *f = GDCM_NAME_SPACE::File::New();
153    f->SetLoadMode( loadMode );
154
155    f->SetFileName( fileName );
156    bool res = f->Load();  
157       if ( !res )
158    {
159       f->Delete();
160       return 0;
161    }
162
163    if (!f->IsReadable())
164    {
165        std::cerr << "Sorry, not a Readable DICOM / ACR File"  <<std::endl;
166        f->Delete();
167        return 0;
168    }
169    
170    GDCM_NAME_SPACE::FileHelper *fh = GDCM_NAME_SPACE::FileHelper::New(f);
171    void *imageData; 
172    int dataSize;
173  
174     int nX,nY,nZ,sPP,planarConfig;
175    std::string pixelType, transferSyntaxName;
176    nX=f->GetXSize();
177    nY=f->GetYSize();
178    nZ=f->GetZSize();
179    
180    std::cout << " DIMX=" << nX << " DIMY=" << nY << " DIMZ=" << nZ << std::endl;
181
182    pixelType    = f->GetPixelType();
183    sPP          = f->GetSamplesPerPixel();
184    planarConfig = f->GetPlanarConfiguration();
185    
186    std::cout << " pixelType="           << pixelType 
187              << " SampleserPixel="      << sPP
188              << " PlanarConfiguration=" << planarConfig 
189              << " PhotometricInterpretation=" 
190              << f->GetEntryString(0x0028,0x0004) 
191              << std::endl;
192
193    int numberOfScalarComponents=f->GetNumberOfScalarComponents();
194    std::cout << "NumberOfScalarComponents " << numberOfScalarComponents 
195              <<std::endl;
196    transferSyntaxName = f->GetTransferSyntaxName();
197    std::cout << " TransferSyntaxName= [" << transferSyntaxName << "]" 
198              << std::endl;
199   
200    if(monochrome1)
201       fh->SetPhotometricInterpretationToMonochrome1();
202    
203    if (rgb)
204    {
205       dataSize  = fh->GetImageDataSize();
206       imageData = fh->GetImageData(); // somewhat important : Loads the Pixels in memory !
207       fh->SetWriteModeToRGB();
208    }
209    else
210    {
211       dataSize  = fh->GetImageDataRawSize();
212       imageData = fh->GetImageDataRaw();// somewhat important : Loads the Pixels in memory !
213       fh->SetWriteModeToRaw();
214    }
215
216    if ( imageData == 0 ) // to avoid warning
217    {
218       std::cout << "Was unable to read pixels " << std::endl;
219    }
220    printf(" dataSize %d imageData %p\n",dataSize, imageData);
221
222    // Since we just ReWrite the image, we know no modification 
223    // was performed on the pixels.
224    // We don't want this image appears as a 'Secondary Captured image'
225    fh->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
226    
227
228    /// \todo : think about rubbing out a part of a *multiframe* image!
229    if (rubout)
230    {     
231       if (boundVal[0]<0 || boundVal[0]>nX)
232       { 
233          std::cout << "xBegin out of bounds; 'rubout' ignored" << std::endl;
234          fail = true;      
235       }
236       if (boundVal[1]<0 || boundVal[1]>nX)
237       { 
238          std::cout << "xEnd out of bounds; 'rubout' ignored" << std::endl;
239          fail = true;      
240       }
241       if (boundVal[0] > boundVal[1])
242       { 
243          std::cout << "xBegin greater than xEnd; 'rubout' ignored" << std::endl;
244          fail = true;      
245       }       
246       if (boundVal[2]<0 || boundVal[2]>nY)
247       { 
248          std::cout << "yBegin out of bounds; 'rubout' ignored" << std::endl;
249          fail = true;      
250       }
251       if (boundVal[3]<0 || boundVal[3]>nY)
252       { 
253          std::cout << "yEnd out of bounds; 'rubout' ignored" << std::endl;
254          fail = true;      
255       }
256       if (boundVal[2] > boundVal[3])
257       { 
258          std::cout << "yBegin greater than yEnd; 'rubout' ignored" << std::endl;
259          fail = true;      
260       }  
261       if (!fail)
262       {
263          int pixelLength = f->GetBitsAllocated()/8;
264          int lineLength = nX * sPP * pixelLength;
265          size_t lengthToRubout = (boundVal[1]-boundVal[0])*sPP*pixelLength;
266          int offsetToBeginOfRubout = boundVal[0]*sPP*pixelLength+lineLength*boundVal[2];
267       
268          for(int rbl=boundVal[2]; rbl<boundVal[3];rbl++)
269          {
270             memset((char *)imageData+offsetToBeginOfRubout, ruboutVal, lengthToRubout);
271             offsetToBeginOfRubout += lineLength; 
272          }
273       }   
274    } 
275
276 //
277 // user wants to keep only a part of the image (ROI, and/or some frames)
278 // ---------------------------------------------------------------------
279 // (==> this is no longer really 'ReWrite' !)
280
281     int subImDimX = nX;
282     int subImDimY = nY;    
283
284     if (roi)
285     {  
286       if (roiBoundVal[0]<0 || roiBoundVal[0]>=nX)
287       { 
288          std::cout << "xBegin out of bounds; 'roi' ignored" << std::endl;
289          fail = true;      
290       }
291       if (roiBoundVal[1]<0 || roiBoundVal[1]>=nX)
292       { 
293          std::cout << "xEnd out of bounds; 'roi' ignored" << std::endl;
294          fail = true;      
295       }
296       if (roiBoundVal[0] > roiBoundVal[1])
297       { 
298          std::cout << "xBegin greater than xEnd; 'roi' ignored" << std::endl;
299          fail = true;      
300       }
301
302       if (roiBoundVal[2]<0 || roiBoundVal[2]>=nY)
303       { 
304          std::cout << "yBegin out of bounds; 'roi' ignored" << std::endl;
305          fail = true;      
306       }
307       if (roiBoundVal[3]<0 || roiBoundVal[3]>=nY)
308       { 
309          std::cout << "yEnd out of bounds; 'roi' ignored" << std::endl;
310          fail = true;      
311       }
312       if (roiBoundVal[2] > roiBoundVal[3])
313       { 
314          std::cout << "yBegin greater than yEnd; 'roi' ignored" << std::endl;
315          fail = true;      
316       }  
317    } 
318    else
319    {  
320      roiBoundVal = new int[4];
321      roiBoundVal[0] = 0;
322      roiBoundVal[1] = nX-1;
323      roiBoundVal[2] = 0;
324      roiBoundVal[3] = nY-1;  
325   }
326
327    subImDimX = roiBoundVal[1]-roiBoundVal[0]+1;     
328    subImDimY = roiBoundVal[3]-roiBoundVal[2]+1;  
329  
330   if (roi || beg != -1 || end != -1)
331   {  
332      if (beg == -1)
333         beg = 0;  
334      if (end == -1)
335         end = nZ-1;
336      
337      std::ostringstream str;
338      
339     // Set the data that will be *actually* written.
340
341      int pixelSize = fh->GetFile()->GetPixelSize();
342      size_t lgrSubLine  = subImDimX* pixelSize * numberOfScalarComponents;
343      size_t lgrSubFrame = subImDimY*lgrSubLine;
344                       ;
345      int lgrSubImage = (end-beg+1) * lgrSubFrame;
346        
347      uint8_t * subImage = new uint8_t[lgrSubImage];
348        
349      uint8_t * srcCopy = (uint8_t *) imageData;
350      uint8_t * destCopy = subImage;
351      int lineSize = nX*pixelSize*numberOfScalarComponents;
352      int frameSize = nY*lineSize; 
353  
354      int lineOffset = roiBoundVal[0]*pixelSize * numberOfScalarComponents;
355      
356      for (int frameNb=beg, frameCount=0; frameNb<=end; frameNb++, frameCount++)
357      { 
358         for (int lineNb=roiBoundVal[2], lineCount=0; lineNb<=roiBoundVal[3]; lineNb++, lineCount++)
359         {  
360             /// \todo increment data pointer, don't multiply so much!
361             memcpy( (void *)(destCopy + frameCount*lgrSubFrame + lineCount*lgrSubLine), 
362                     (void *)(srcCopy  + frameNb*frameSize + lineNb*lineSize + lineOffset ), 
363                     lgrSubLine);
364         }        
365      }
366  
367     // Set the image size
368      str.str("");
369      str << subImDimX ;
370      fh->InsertEntryString(str.str(),0x0028,0x0011,"US"); // Columns
371
372      str.str("");
373      str << subImDimY;
374      fh->InsertEntryString(str.str(),0x0028,0x0010,"US"); // Rows
375      str.str("");
376      str << end-beg+1; 
377      fh->InsertEntryString(str.str(),0x0028,0x0008, "IS"); // Number of Frames 
378       
379      fh->SetImageData(subImage,lgrSubImage);
380             
381   }     
382
383
384 //----------------------------------- Write, now! ---------------------------------
385
386    switch (mode[0])
387    {
388       case 'A' :
389       case 'a' :
390       // Writting an ACR file
391       // from a full gdcm readable File
392          std::cout << "WriteACR" << std::endl;
393          fh->WriteAcr(outputFileName);
394          break;
395
396       case 'D' : // Not documented in the 'usage', because the method 
397       case 'd' : //                             is known to be bugged. 
398       // Writting a DICOM Implicit VR file
399       // from a full gdcm readable File
400          std::cout << "WriteDCM Implicit VR" << std::endl;
401          fh->WriteDcmImplVR(outputFileName);
402          break;
403
404       case 'X' :
405       case 'x' :
406       // writting a DICOM Explicit VR 
407       // from a full gdcm readable File
408          std::cout << "WriteDCM Explicit VR" << std::endl;
409          // fh->WriteDcmExplVR(outputFileName);
410          // Try this one :
411          fh->SetWriteTypeToDcmExplVR();
412          fh->Write(outputFileName);
413          break;
414
415       case 'R' :
416       case 'r' :
417       //  Writting a Raw File, 
418          std::cout << "WriteRaw" << std::endl;
419          fh->WriteRawData(outputFileName);
420          break;
421  
422  // Just for fun :
423  // Write a 'Video inverse' version of the file.
424  // *Not* described, on purpose,  in the USAGE  
425       case 'V' :
426       case 'v' :
427          if ( fh->GetFile()->GetBitsAllocated() == 8)
428          {
429             std::cout << "videoinv for 8 bits" << std::endl;
430             for (int i=0; i<dataSize; i++) 
431             {
432                ((uint8_t*)imageData)[i] = 255 - ((uint8_t*)imageData)[i];
433             }
434          }
435          else
436          {
437             std::cout << "videoinv for 16 bits" << std::endl;    
438             for (int i=0; i<dataSize/2; i++) 
439             {
440                ((uint16_t*)imageData)[i] =  65535 - ((uint16_t*)imageData)[i];
441             }
442          }
443          std::cout << "WriteDCM Explicit VR + VideoInv" << std::endl;
444          fh->WriteDcmExplVR(outputFileName);
445          break;
446    }
447
448    f->Delete();
449    fh->Delete();
450    return 0;
451 }
452
453