]> Creatis software - gdcm.git/blob - Example/RawToDicom.cxx
ENH: fix link + update info
[gdcm.git] / Example / RawToDicom.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: RawToDicom.cxx,v $
5   Language:  C++
6   Date:      $Date: 2008/06/12 13:21:20 $
7   Version:   $Revision: 1.16 $
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", "g^Fantomas");
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
118    bool userDefinedStudy = ( 0 != am->ArgMgrDefined("studyUID") );
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    const char *serieUID;
126    if(userDefinedSerie)
127       serieUID = am->ArgMgrGetString("serieUID");
128
129    /* if unused Param we give up */
130    if ( am->ArgMgrPrintUnusedLabels() )
131    {
132       am->ArgMgrUsage(usage);
133       delete am;
134       return 1;
135    } 
136
137    delete am;  // we don't need Argument Manager any longer
138
139    // ----------- End Arguments Manager ---------
140    
141  /// \TODO Deal with all the images of a directory
142   
143  // Read the Raw file  
144    std::ifstream *Fp = new std::ifstream(inputFileName, std::ios::in | std::ios::binary);
145    if ( ! *Fp )
146    {   
147       std::cout << "Cannot open file: " << inputFileName;
148       delete Fp;
149       Fp = 0;
150       return 0;
151    }  
152
153    bool bigEndian = GDCM_NAME_SPACE::Util::IsCurrentProcessorBigEndian();
154
155    std::string strPixelType(pixelType);
156    int pixelSign;
157    int pixelSize;
158    
159    if (strPixelType == "8S")
160    {
161       pixelSize = 1;
162       pixelSign = 1;
163    }
164    else if (strPixelType == "8U")
165    {
166       pixelSize = 1;
167       pixelSign = 0;
168    }
169    else if (strPixelType == "16S")
170    {
171       pixelSize = 2;
172       pixelSign = 1;
173    }   
174    else if (strPixelType == "16U")
175    {
176       pixelSize = 2;
177       pixelSign = 0;
178    }      
179    else if (strPixelType == "32S")
180    {
181       pixelSize = 4;
182       pixelSign = 1;
183    }   
184    else if (strPixelType == "32U")
185    {
186       pixelSize = 4;
187       pixelSign = 0;
188    }
189    else
190    {
191       std::cout << "Wrong 'pixeltype' (" << strPixelType << ")" << std::endl;
192       return 1;
193    }
194
195    std::string strStudyUID;
196    std::string strSerieUID;
197
198    if (userDefinedStudy)
199       strSerieUID = studyUID;
200    else
201       strStudyUID = GDCM_NAME_SPACE::Util::CreateUniqueUID();
202    
203    if (userDefinedSerie)
204      strSerieUID = serieUID;
205    else
206       strSerieUID = GDCM_NAME_SPACE::Util::CreateUniqueUID();
207       
208    // Read the pixels
209
210    int dataSize =  nX*nY*nZ*samplesPerPixel*pixelSize;
211
212    uint8_t *pixels = new uint8_t[dataSize];
213    
214    Fp->read((char*)pixels, (size_t)dataSize);
215      
216    if ( pixelSize !=1 && ( (l && bigEndian) || (b && ! bigEndian) ) )
217    {  
218       ConvertSwapZone(pixelSize, pixels, dataSize);   
219    }
220
221 // Create an empty FileHelper
222
223    GDCM_NAME_SPACE::FileHelper *fileH = GDCM_NAME_SPACE::FileHelper::New();
224  
225  // Get the (empty) image header.
226    GDCM_NAME_SPACE::File *fileToBuild = fileH->GetFile();
227
228    // 'Study Instance UID'
229    // The user is allowed to create his own Study, 
230    //          keeping the same 'Study Instance UID' for various images
231    // The user may add images to a 'Manufacturer Study',
232    //          adding new Series to an already existing Study
233
234    fileToBuild->InsertEntryString(strStudyUID,0x0020,0x000d,"UI");  //  Study UID   
235
236    // 'Serie Instance UID'
237    // The user is allowed to create his own Series, 
238    // keeping the same 'Serie Instance UID' for various images
239    // The user shouldn't add any image to a 'Manufacturer Serie'
240    // but there is no way no to prevent him for doing that
241    
242    fileToBuild->InsertEntryString(strSerieUID,0x0020,0x000e,"UI");  //  Serie UID
243    
244    std::ostringstream str;
245
246    // Set the image size
247    str.str("");
248    str << nX;
249    fileToBuild->InsertEntryString(str.str(),0x0028,0x0011, "US"); // Columns
250    str.str("");
251    str << nY;
252    fileToBuild->InsertEntryString(str.str(),0x0028,0x0010, "US"); // Rows
253    
254    str.str("");
255    str << nZ;
256    fileToBuild->InsertEntryString(str.str(),0x0028,0x0008, "IS"); // Number of Frames
257
258    // Set the pixel type
259    
260    str.str("");
261    str << pixelSize*8;
262    fileToBuild->InsertEntryString(str.str(),0x0028,0x0100, "US"); // Bits Allocated
263
264    str.str("");
265    str << pixelSize*8;
266    fileToBuild->InsertEntryString(str.str(),0x0028,0x0101, "US"); // Bits Stored
267
268    str.str("");
269    str << ( pixelSize*8 - 1 );
270    fileToBuild->InsertEntryString(str.str(),0x0028,0x0102, "US"); // High Bit
271
272    str.str("");
273    str << pixelSign;
274    fileToBuild->InsertEntryString(str.str(),0x0028,0x0103, "US"); // Pixel Representation
275
276    str.str("");
277    str << samplesPerPixel;
278    
279 // If you deal with a Serie of images, as slices of a volume,
280 // it up to you to tell gdcm, for each image, what are the values of :
281 // 
282 // 0020 0032 DS 3 Image Position (Patient)
283 // 0020 0037 DS 6 Image Orientation (Patient)
284
285    fileToBuild->InsertEntryString(str.str(),0x0028,0x0002, "US"); // Samples per Pixel
286
287    if (strlen(patientName) != 0)
288       fileToBuild->InsertEntryString(patientName,0x0010,0x0010, "PN"); // Patient's Name
289     
290    //  0=white  
291    if(monochrome1)
292       fileH->SetPhotometricInterpretationToMonochrome1();
293      
294 // Set the image Pixel Data
295    fileH->SetImageData(pixels,dataSize);
296
297 // Set the writting mode and write the image
298    fileH->SetWriteModeToRaw();
299
300  // Write a DICOM Explicit VR file
301    fileH->SetWriteTypeToDcmExplVR();
302
303    if( !fileH->Write(outputFileName ) )
304    {
305       std::cout << "Failed for [" << outputFileName << "]\n"
306                 << "           File is unwrittable\n";
307    }
308
309    fileH->Delete();
310
311    delete[] pixels;
312    return 1;
313 }