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