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