]> Creatis software - gdcm.git/blob - Example/RawToDicom.cxx
Avoid poluating 'Series Descr" with full path name
[gdcm.git] / Example / RawToDicom.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: RawToDicom.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/09/20 11:15:54 $
7   Version:   $Revision: 1.14 $
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
19 /**
20  * Writes a Dicom file from a Raw File
21  * User has to supply parameters. 
22  * 
23  */
24 #include "gdcmFile.h"
25 #include "gdcmFileHelper.h"
26 #include "gdcmDebug.h"
27 #include "gdcmUtil.h"
28 #include "gdcmArgMgr.h"
29
30 #include <iostream>
31 #include <sstream>
32
33 void ConvertSwapZone(int pixelSize, void *Raw, size_t RawSize);
34
35 void ConvertSwapZone(int pixelSize, void *Raw, size_t RawSize)
36 {
37    unsigned int i;    
38    if ( pixelSize == 2 )
39    {
40       uint16_t *im16 = (uint16_t*)Raw;
41       for( i = 0; i < RawSize / 2; i++ )
42       {
43          im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
44       }     
45    }
46    else if ( pixelSize == 4 )
47    {
48       uint32_t s32;
49       uint16_t high;
50       uint16_t low;
51       uint32_t *im32 = (uint32_t*)Raw;
52
53       for( i = 0; i < RawSize / 4; i++ )
54       {
55          low     = im32[i] & 0x0000ffff; // 3412
56          high    = im32[i] >> 16;
57          s32     = low;
58          im32[i] = ( s32 << 16 ) | high;
59       }
60       
61    }
62 }
63
64 int main(int argc, char *argv[])
65 {
66    START_USAGE(usage)
67    " \n RawToDicom : \n                                                       ",
68    " Writes a Dicom file from a Raw File                                      ",
69    " usage: RawToDicom filein=inputFileName                                   ",
70    "                   fileout=outputFileName                                 ",
71    "                   rows=nb of Rows                                        ",
72    "                   lines=nb of Lines,                                     ",
73    "                   [frames = nb of Frames] //defaulted to 1               ",
74    "                   pixeltype={8U|8S|16U|16S|32U|32S}                      ",
75    "                   [{b|l}] b:BigEndian,l:LittleEndian default : l         ",
76    "                   [samples = {1|3}}       //(1:Gray,3:RGB) defaulted to 1",
77    "                   [monochrome1]                                          ",
78    "                   [studyid = ] [patientname = Patient's name]            ",
79    "                   [debug]                                                ",
80    "                                                                          ",
81    "  monochrome1 = user wants MONOCHROME1 photom. interp. (0=white)          ", 
82    "  studyUID   : *aware* user wants to add the serie                        ",
83    "                                             to an already existing study ",
84    "  debug      : developper wants to run the program in 'debug mode'        ",
85    FINISH_USAGE
86    
87
88    // ------------ Initialize Arguments Manager ----------------  
89    GDCM_NAME_SPACE::ArgMgr *am= new GDCM_NAME_SPACE::ArgMgr(argc, argv);
90   
91    if (argc == 1 || am->ArgMgrDefined("usage") )
92    {
93       am->ArgMgrUsage(usage); // Display 'usage'
94       delete am;
95       return 1;
96    }
97
98    const char *inputFileName  = am->ArgMgrGetString("filein");
99    const char *outputFileName = am->ArgMgrGetString("fileout");
100    
101    const char *patientName = am->ArgMgrGetString("patientname");
102    
103    int nX = am->ArgMgrWantInt("rows", usage);
104    int nY = am->ArgMgrWantInt("lines", usage);
105    int nZ = am->ArgMgrGetInt("frames", 1);
106    int samplesPerPixel = am->ArgMgrGetInt("samples", 1);
107    
108    int b = am->ArgMgrDefined("b");
109    int l = am->ArgMgrDefined("l");
110       
111    char *pixelType = am->ArgMgrWantString("pixeltype", usage);
112
113    bool monochrome1 = ( 0 != am->ArgMgrDefined("monochrome1") );
114       
115    if (am->ArgMgrDefined("debug"))
116       GDCM_NAME_SPACE::Debug::DebugOn();
117    bool userDefinedStudy = ( 0 != am->ArgMgrDefined("studyUID") );
118
119    const char *studyUID;
120    if (userDefinedStudy)
121       studyUID  = am->ArgMgrGetString("studyUID");  
122
123    // not described *on purpose* in the Usage !
124    bool userDefinedSerie = ( 0 != am->ArgMgrDefined("serieUID") );       
125
126    const char *serieUID;
127    if(userDefinedSerie)
128       serieUID = am->ArgMgrGetString("serieUID");
129
130    /* if unused Param we give up */
131    if ( am->ArgMgrPrintUnusedLabels() )
132    {
133       am->ArgMgrUsage(usage);
134       delete am;
135       return 1;
136    } 
137
138    delete am;  // we don't need Argument Manager any longer
139
140    // ----------- End Arguments Manager ---------
141    
142  /// \TODO Deal with all the images of a directory
143   
144  // Read the Raw file  
145    std::ifstream *Fp = new std::ifstream(inputFileName, std::ios::in | std::ios::binary);
146    if ( ! *Fp )
147    {   
148       std::cout << "Cannot open file: " << inputFileName;
149       delete Fp;
150       Fp = 0;
151       return 0;
152    }  
153
154    bool bigEndian = GDCM_NAME_SPACE::Util::IsCurrentProcessorBigEndian();
155
156    std::string strPixelType(pixelType);
157    int pixelSign;
158    int pixelSize;
159    
160    if (strPixelType == "8S")
161    {
162       pixelSize = 1;
163       pixelSign = 1;
164    }
165    else if (strPixelType == "8U")
166    {
167       pixelSize = 1;
168       pixelSign = 0;
169    }
170    else if (strPixelType == "16S")
171    {
172       pixelSize = 2;
173       pixelSign = 1; 
174    }   
175    else if (strPixelType == "16U")
176    {
177       pixelSize = 2;
178       pixelSign = 0;
179    }      
180    else if (strPixelType == "32S")
181    {
182       pixelSize = 4;
183       pixelSign = 1;
184    }   
185    else if (strPixelType == "32U")
186    {
187       pixelSize = 4;
188       pixelSign = 0;
189    }
190    else
191    {
192       std::cout << "Wrong 'pixeltype' (" << strPixelType << ")" << std::endl;
193       return 1;
194    }
195  
196    std::string strStudyUID;
197    std::string strSerieUID;
198
199    if (userDefinedStudy)
200       strSerieUID =  studyUID;
201    else
202       strStudyUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
203    
204    if (userDefinedStudy)
205      strSerieUID =  serieUID;
206    else
207       strStudyUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();  
208       
209         
210    int dataSize =  nX*nY*nZ*pixelSize*samplesPerPixel;
211    uint8_t *pixels = new uint8_t[dataSize];
212    
213    Fp->read((char*)pixels, (size_t)dataSize);
214      
215    if ( pixelSize !=1 && ( (l && bigEndian) || (b && ! bigEndian) ) )
216    {  
217       ConvertSwapZone(pixelSize, pixels, dataSize);   
218    }   
219    
220 // Create an empty FileHelper
221
222    GDCM_NAME_SPACE::FileHelper *fileH = GDCM_NAME_SPACE::FileHelper::New();
223  
224  // Get the (empty) image header.  
225    GDCM_NAME_SPACE::File *fileToBuild = fileH->GetFile();
226
227    // 'Study Instance UID'
228    // The user is allowed to create his own Study, 
229    //          keeping the same 'Study Instance UID' for various images
230    // The user may add images to a 'Manufacturer Study',
231    //          adding new Series to an already existing Study
232
233    fileToBuild->InsertEntryString(strStudyUID,0x0020,0x000d,"UI");  //  Study UID   
234
235    // 'Serie Instance UID'
236    // The user is allowed to create his own Series, 
237    // keeping the same 'Serie Instance UID' for various images
238    // The user shouldn't add any image to a 'Manufacturer Serie'
239    // but there is no way no to prevent him for doing that
240    
241    fileToBuild->InsertEntryString(strSerieUID,0x0020,0x000e,"UI");  //  Serie UID
242    
243    std::ostringstream str;
244
245    // Set the image size
246    str.str("");
247    str << nX;
248    fileToBuild->InsertEntryString(str.str(),0x0028,0x0011, "US"); // Columns
249    str.str("");
250    str << nY;
251    fileToBuild->InsertEntryString(str.str(),0x0028,0x0010, "US"); // Rows
252    
253    str.str("");
254    str << nZ;
255    fileToBuild->InsertEntryString(str.str(),0x0028,0x0008, "IS"); // Number of Frames
256
257    // Set the pixel type
258    
259    str.str("");
260    str << pixelSize*8;
261    fileToBuild->InsertEntryString(str.str(),0x0028,0x0100, "US"); // Bits Allocated
262
263    str.str("");
264    str << pixelSize*8;
265    fileToBuild->InsertEntryString(str.str(),0x0028,0x0101, "US"); // Bits Stored
266
267    str.str("");
268    str << ( pixelSize*8 - 1 );
269    fileToBuild->InsertEntryString(str.str(),0x0028,0x0102, "US"); // High Bit
270
271    str.str("");
272    str << pixelSign;
273    fileToBuild->InsertEntryString(str.str(),0x0028,0x0103, "US"); // Pixel Representation
274
275    str.str("");
276    str << samplesPerPixel;
277    
278 // If you deal with a Serie of images, as slices of a volume,
279 // it up to you to tell gdcm, for each image, what are the values of :
280 // 
281 // 0020 0032 DS 3 Image Position (Patient)
282 // 0020 0037 DS 6 Image Orientation (Patient)
283
284    fileToBuild->InsertEntryString(str.str(),0x0028,0x0002, "US"); // Samples per Pixel
285
286    if (strlen(patientName) != 0)
287       fileToBuild->InsertEntryString(patientName,0x0010,0x0010, "PN"); // Patient's Name
288     
289    //  0=white  
290    if(monochrome1)
291       fileH->SetPhotometricInterpretationToMonochrome1();
292      
293 // Set the image Pixel Data
294    fileH->SetImageData(pixels,dataSize);
295
296 // Set the writting mode and write the image
297    fileH->SetWriteModeToRaw();
298
299  // Write a DICOM Explicit VR file
300    fileH->SetWriteTypeToDcmExplVR();
301
302    if( !fileH->Write(outputFileName ) )
303    {
304       std::cout << "Failed for [" << outputFileName << "]\n"
305                 << "           File is unwrittable\n";
306    }
307
308    fileH->Delete();
309
310    delete[] pixels;
311    return 1;
312 }