]> Creatis software - gdcm.git/blob - vtk/vtkGdcmWriter.cxx
* vtk/vtkGdcmWriter.[h|cxx] : add the gestion of UID
[gdcm.git] / vtk / vtkGdcmWriter.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: vtkGdcmWriter.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/01/28 10:07:35 $
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 #include "gdcmFile.h"
20 #include "gdcmFileHelper.h"
21 #include "gdcmDebug.h"
22 #include "gdcmUtil.h"
23 #include "vtkGdcmWriter.h"
24
25 #include <vtkObjectFactory.h>
26 #include <vtkImageData.h>
27 #include <vtkPointData.h>
28 #include <vtkLookupTable.h>
29
30 vtkCxxRevisionMacro(vtkGdcmWriter, "$Revision: 1.16 $");
31 vtkStandardNewMacro(vtkGdcmWriter);
32
33 //-----------------------------------------------------------------------------
34 // Constructor / Destructor
35 vtkGdcmWriter::vtkGdcmWriter()
36 {
37    this->LookupTable = NULL;
38    this->FileDimensionality = 3;
39    this->WriteType = VTK_GDCM_WRITE_TYPE_EXPLICIT_VR;
40
41    UIDPrefix = "";
42    StudyInstanceUID = "";
43    SeriesInstanceUID = "";
44    FrameOfReferenceInstanceUID = "";
45 }
46
47 vtkGdcmWriter::~vtkGdcmWriter()
48 {
49 }
50
51 //-----------------------------------------------------------------------------
52 // Print
53 void vtkGdcmWriter::PrintSelf(ostream& os, vtkIndent indent)
54 {
55    this->Superclass::PrintSelf(os,indent);
56
57    os << indent << "Write type : " << this->GetWriteTypeAsString();
58 }
59
60 //-----------------------------------------------------------------------------
61 // Public
62 const char *vtkGdcmWriter::GetWriteTypeAsString()
63 {
64    switch(WriteType)
65    {
66       case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
67          return "Explicit VR";
68       case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
69          return "Implicit VR";
70       case VTK_GDCM_WRITE_TYPE_ACR :
71          return "ACR";
72       case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
73          return "ACR Libido";
74       default :
75          return "Unknow type";
76    }
77 }
78
79 void vtkGdcmWriter::SetUIDPrefix(const char *prefix)
80 {
81    UIDPrefix = prefix;
82 }
83
84 const char *vtkGdcmWriter::GetUIDPrefix()
85 {
86    return UIDPrefix.c_str();
87 }
88
89 void vtkGdcmWriter::NewStudyInstanceUID()
90 {
91    StudyInstanceUID = "";
92 }
93
94 void vtkGdcmWriter::NewSeriesInstanceUID()
95 {
96    SeriesInstanceUID = "";
97 }
98
99 void vtkGdcmWriter::NewFrameOfReferenceInstanceUID()
100 {
101    FrameOfReferenceInstanceUID = "";
102 }
103
104 //-----------------------------------------------------------------------------
105 // Protected
106 /**
107  * Copy the image and reverse the Y axis
108  */
109 // The output datas must be deleted by the user of the method !!!
110 size_t ReverseData(vtkImageData *image,unsigned char **data)
111 {
112    int inc[3];
113    int *extent = image->GetUpdateExtent();
114    int dim[3] = {extent[1]-extent[0]+1,
115                  extent[3]-extent[2]+1,
116                  extent[5]-extent[4]+1};
117
118    size_t lineSize = dim[0] * image->GetScalarSize()
119                    * image->GetNumberOfScalarComponents();
120    size_t planeSize = dim[1] * lineSize;
121    size_t size = dim[2] * planeSize;
122
123    if( size>0 )
124    {
125       *data = new unsigned char[size];
126
127       image->GetIncrements(inc);
128       unsigned char *src = (unsigned char *)image->GetScalarPointerForExtent(extent);
129       unsigned char *dst = *data + planeSize - lineSize;
130       for (int plane = extent[4]; plane <= extent[5]; plane++)
131       {
132          for (int line = extent[2]; line <= extent[3]; line++)
133          {
134             // Copy one line at proper destination:
135             memcpy((void*)dst, (void*)src, lineSize);
136
137             src += inc[1] * image->GetScalarSize();
138             dst -= lineSize;
139          }
140          dst += 2 * planeSize;
141       }
142    }
143    else
144    {
145       *data = NULL;
146    }
147
148    return size;
149 }
150
151 /**
152  * Set the datas informations in the file
153  */
154 void SetImageInformation(gdcm::FileHelper *file,vtkImageData *image)
155 {
156    std::ostringstream str;
157
158    // Image size
159    int *extent = image->GetUpdateExtent();
160    int dim[3] = {extent[1]-extent[0]+1,
161                  extent[3]-extent[2]+1,
162                  extent[5]-extent[4]+1};
163
164    str.str("");
165    str << dim[0];
166    file->InsertValEntry(str.str(),0x0028,0x0011); // Columns
167
168    str.str("");
169    str << dim[1];
170    file->InsertValEntry(str.str(),0x0028,0x0010); // Rows
171
172    if(dim[2]>1)
173    {
174       str.str("");
175       str << dim[2];
176       //file->Insert(str.str(),0x0028,0x0012); // Planes
177       file->InsertValEntry(str.str(),0x0028,0x0008); // Number of Frames
178    }
179
180    // Pixel type
181    str.str("");
182    str << image->GetScalarSize()*8;
183    file->InsertValEntry(str.str(),0x0028,0x0100); // Bits Allocated
184    file->InsertValEntry(str.str(),0x0028,0x0101); // Bits Stored
185
186    str.str("");
187    str << image->GetScalarSize()*8-1;
188    file->InsertValEntry(str.str(),0x0028,0x0102); // High Bit
189
190    // Pixel Repr
191    // FIXME : what do we do when the ScalarType is 
192    // VTK_UNSIGNED_INT or VTK_UNSIGNED_LONG
193    str.str("");
194    if( image->GetScalarType() == VTK_UNSIGNED_CHAR ||
195        image->GetScalarType() == VTK_UNSIGNED_SHORT ||
196        image->GetScalarType() == VTK_UNSIGNED_INT ||
197        image->GetScalarType() == VTK_UNSIGNED_LONG )
198    {
199       str << "0"; // Unsigned
200    }
201    else
202    {
203       str << "1"; // Signed
204    }
205    file->InsertValEntry(str.str(),0x0028,0x0103); // Pixel Representation
206
207    // Samples per pixel
208    str.str("");
209    str << image->GetNumberOfScalarComponents();
210    file->InsertValEntry(str.str(),0x0028,0x0002); // Samples per Pixel
211
212    // Spacing
213    double *sp = image->GetSpacing();
214
215    str.str("");
216    str << sp[0] << "\\" << sp[1];
217    file->InsertValEntry(str.str(),0x0028,0x0030); // Pixel Spacing
218    str.str("");
219    str << sp[2];
220    file->InsertValEntry(str.str(),0x0018,0x0088); // Spacing Between Slices
221
222    // Origin
223    double *org = image->GetOrigin();
224
225    str.str("");
226    str << org[0] << "\\" << org[1] << "\\" << org[2];
227    file->InsertValEntry(str.str(),0x0020,0x0032); // Image Position Patient
228
229    // Window / Level
230    double *rng=image->GetScalarRange();
231
232    str.str("");
233    str << rng[1]-rng[0];
234    file->InsertValEntry(str.str(),0x0028,0x1051); // Window Width
235    str.str("");
236    str << (rng[1]+rng[0])/2.0;
237    file->InsertValEntry(str.str(),0x0028,0x1050); // Window Center
238
239    // Pixels
240    unsigned char *data;
241    size_t size = ReverseData(image,&data);
242    file->SetUserData(data,size);
243 }
244
245 /**
246  * Write of the files
247  * The call to this method is recursive if there is some files to write
248  */ 
249 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *image, ofstream *file)
250 {
251    if(file)
252    {
253       vtkErrorMacro( <<  "File musn't be opened");
254       return;
255    }
256
257    if( image->GetScalarType() == VTK_FLOAT || 
258        image->GetScalarType() == VTK_DOUBLE )
259    {
260       vtkErrorMacro(<< "Bad input type. Scalar type musn't be of type "
261                     << "VTK_FLOAT or VTKDOUBLE (found:"
262                     << image->GetScalarTypeAsString());
263       return;
264    }
265
266    RecursiveWrite(axis,image,image,file);
267    //WriteDcmFile(this->FileName,image);
268 }
269
270 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *cache, 
271                                    vtkImageData *image, ofstream *file)
272 {
273    int idx, min, max;
274
275    // if the file is already open then just write to it
276    if( file )
277    {
278       vtkErrorMacro( <<  "File musn't be opened");
279       return;
280    }
281
282    // if we need to open another slice, do it
283    if( (axis + 1) == this->FileDimensionality )
284    {
285       // determine the name
286       if (this->FileName)
287       {
288          sprintf(this->InternalFileName,"%s",this->FileName);
289       }
290       else 
291       {
292          if (this->FilePrefix)
293          {
294             sprintf(this->InternalFileName, this->FilePattern, 
295             this->FilePrefix, this->FileNumber);
296          }
297          else
298          {
299             sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
300          }
301          if (this->FileNumber < this->MinimumFileNumber)
302          {
303             this->MinimumFileNumber = this->FileNumber;
304          }
305          else if (this->FileNumber > this->MaximumFileNumber)
306          {
307             this->MaximumFileNumber = this->FileNumber;
308          }
309       }
310
311       // Write the file
312       WriteDcmFile(this->InternalFileName,image);
313       ++this->FileNumber;
314       return;
315    }
316
317    // if the current region is too high a dimension forthe file
318    // the we will split the current axis
319    cache->GetAxisUpdateExtent(axis, min, max);
320
321    // if it is the y axis then flip by default
322    if (axis == 1 && !this->FileLowerLeft)
323    {
324       for(idx = max; idx >= min; idx--)
325       {
326          cache->SetAxisUpdateExtent(axis, idx, idx);
327          this->RecursiveWrite(axis - 1, cache, image, file);
328       }
329    }
330    else
331    {
332       for(idx = min; idx <= max; idx++)
333       {
334          cache->SetAxisUpdateExtent(axis, idx, idx);
335          this->RecursiveWrite(axis - 1, cache, image, file);
336       }
337    }
338
339    // restore original extent
340    cache->SetAxisUpdateExtent(axis, min, max);
341 }
342
343 void vtkGdcmWriter::WriteDcmFile(char *fileName,vtkImageData *image)
344 {
345    // From here, the write of the file begins
346    gdcm::FileHelper *dcmFile = new gdcm::FileHelper();
347
348    // Set the image UID
349    if( StudyInstanceUID.empty() )
350       StudyInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
351    if( SeriesInstanceUID.empty() )
352       SeriesInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
353    if( FrameOfReferenceInstanceUID.empty() )
354       FrameOfReferenceInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
355    std::string uid = gdcm::Util::CreateUniqueUID( UIDPrefix );
356
357    dcmFile->InsertValEntry(uid,0x0008,0x0018); //[SOP Instance UID]
358    dcmFile->InsertValEntry(uid,0x0002,0x0003); //[Media Stored SOP Instance UID]
359    dcmFile->InsertValEntry(StudyInstanceUID,0x0020,0x000d); //[Study Instance UID]
360    dcmFile->InsertValEntry(SeriesInstanceUID,0x0020,0x000e); //[Series Instance UID]
361    dcmFile->InsertValEntry(FrameOfReferenceInstanceUID,0x0020, 0x0052); //[Frame of Reference UID] 
362
363    // Set the image informations
364    SetImageInformation(dcmFile,image);
365
366    // Write the image
367    switch(this->WriteType)
368    {
369       case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
370          dcmFile->SetWriteTypeToDcmExplVR();
371          break;
372       case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
373          dcmFile->SetWriteTypeToDcmImplVR();
374          break;
375       case VTK_GDCM_WRITE_TYPE_ACR :
376          dcmFile->SetWriteTypeToAcr();
377          break;
378       case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
379          dcmFile->SetWriteTypeToAcrLibido();
380          break;
381       default :
382          dcmFile->SetWriteTypeToDcmExplVR();
383    }
384
385    if(!dcmFile->Write(fileName))
386    {
387       vtkErrorMacro( << "File "  <<  this->FileName  <<  "couldn't be written by "
388                      << " the gdcm library");
389    }
390
391    // Clean up
392    if( dcmFile->GetUserData() && dcmFile->GetUserDataSize()>0 )
393    {
394       delete[] dcmFile->GetUserData();
395    }
396    delete dcmFile;
397 }
398
399 //-----------------------------------------------------------------------------
400 // Private
401
402 //-----------------------------------------------------------------------------