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