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