2 //-----------------------------------------------------------------------------
3 // //////////////////////////////////////////////////////////////
4 // WARNING TODO CLEANME
5 // Actual limitations of this code:
7 // /////// Redundant and unnecessary header parsing
8 // In it's current state this code actually parses three times the Dicom
9 // header of a file before the corresponding image gets loaded in the
11 // Here is the process:
12 // 1/ First loading happens in ExecuteInformation which in order to
13 // positionate the vtk extents calls CheckFileCoherence. The purpose
14 // of CheckFileCoherence is to make sure all the images in the future
15 // stack are "homogenous" (same size, same representation...). This
16 // can only be achieved by parsing all the Dicom headers...
17 // 2/ ExecuteData is then responsible for the next two loadings:
18 // 2a/ ExecuteData calls AllocateOutputData that in turn seems to
19 // (indirectely call) ExecuteInformation which ends up in a second
21 // This is fixed by adding a test at the beginning of ExecuteInformation
22 // on the modification of the object instance. If a modification have been
23 // made (method Modified() ), the MTime value is increased. The fileTime
24 // is compared to this new value to find a modification in the class
26 // 2b/ the core of ExecuteData then needs gdcmFile (which in turns
27 // initialises gdcmHeader in the constructor) in order to access
31 // maintain a list of gdcmFiles (created by say ExecuteInformation) created
32 // once and for all accross the life of vtkGdcmHeader (it would only load
33 // new gdcmFile if the user changes the list). ExecuteData would then use
34 // those gdcmFile and hence avoid calling the construtor:
35 // - advantage: the header of the files would only be parser once.
36 // - drawback: once execute information is called (i.e. on creation of
37 // a vtkGdcmHeader) the gdcmFile structure is loaded in memory.
38 // The average size of a gdcmHeader being of 100Ko, is one
39 // loads 10 stacks of images with say 200 images each, you
40 // end-up with a loss of 200Mo...
42 // /////// Never unallocated memory:
43 // ExecuteData allocates space for the pixel data [which will get pointed
44 // by the vtkPointData() through the call
45 // data->GetPointData()->GetScalars()->SetVoidArray(mem, StackNumPixels, 0);]
46 // This data is never "freed" neither in the destructor nor when the
47 // filename list is extended, ExecuteData is called a second (or third)
49 // //////////////////////////////////////////////////////////////
51 #include "gdcmHeader.h"
53 #include "gdcmDebug.h"
54 #include "vtkGdcmWriter.h"
56 #include <vtkObjectFactory.h>
57 #include <vtkImageData.h>
58 #include <vtkPointData.h>
59 #include <vtkLookupTable.h>
61 vtkCxxRevisionMacro(vtkGdcmWriter, "$Revision: 1.2 $");
62 vtkStandardNewMacro(vtkGdcmWriter);
64 //-----------------------------------------------------------------------------
65 // Constructor / Destructor
66 vtkGdcmWriter::vtkGdcmWriter()
68 this->LookupTable = NULL;
71 vtkGdcmWriter::~vtkGdcmWriter()
75 //-----------------------------------------------------------------------------
77 void vtkGdcmWriter::PrintSelf(ostream& os, vtkIndent indent)
79 this->Superclass::PrintSelf(os,indent);
82 //-----------------------------------------------------------------------------
85 //-----------------------------------------------------------------------------
87 void SetImageInformation(gdcm::File *file,vtkImageData *image)
89 std::ostringstream str;
92 int *dim = image->GetDimensions();
96 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0011);
100 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0010);
106 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0012);
111 str<<image->GetScalarSize()*8;
112 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0100);
113 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0101);
116 str<<image->GetScalarSize()*8-1;
117 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0102);
120 // FIXME : what do we do when the ScalarType is
121 // VTK_UNSIGNED_INT or VTK_UNSIGNED_LONG
123 if( image->GetScalarType() == VTK_UNSIGNED_CHAR ||
124 image->GetScalarType() == VTK_UNSIGNED_SHORT ||
125 image->GetScalarType() == VTK_UNSIGNED_INT ||
126 image->GetScalarType() == VTK_UNSIGNED_LONG )
128 str<<"0"; // Unsigned
134 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0103);
138 str<<image->GetNumberOfScalarComponents();
139 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0002);
142 double *sp = image->GetSpacing();
145 str<<sp[0]<<"\\"<<sp[1];
146 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x0030);
149 file->ReplaceOrCreateByNumber(str.str(),0x0018,0x0088);
152 double *org = image->GetOrigin();
155 str<<org[0]<<"\\"<<org[1]<<"\\"<<org[2];
156 file->ReplaceOrCreateByNumber(str.str(),0x0020,0x0032);
159 double *rng=image->GetScalarRange();
163 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x1051);
165 str<<(rng[1]+rng[0])/2.0;
166 file->ReplaceOrCreateByNumber(str.str(),0x0028,0x1050);
169 size_t size = dim[0] * dim[1] * dim[2]
170 * image->GetScalarSize()
171 * image->GetNumberOfScalarComponents();
172 file->SetImageData((unsigned char *)image->GetScalarPointer(),size);
175 void vtkGdcmWriter::RecursiveWrite(int dim, vtkImageData *region, ofstream *file)
179 vtkErrorMacro(<< "File musn't be opened");
183 if( region->GetScalarType() == VTK_FLOAT
184 || region->GetScalarType() == VTK_DOUBLE )
186 vtkErrorMacro(<< "Bad input type. Scalar type musn't be of type "
187 << "VTK_FLOAT or VTKDOUBLE (found:"
188 << region->GetScalarTypeAsString());
192 gdcm::File *dcmFile = new gdcm::File();
194 ///////////////////////////////////////////////////////////////////////////
195 // Set the image informations
196 SetImageInformation(dcmFile,region);
198 ///////////////////////////////////////////////////////////////////////////
200 if(!dcmFile->Write(this->FileName))
202 vtkErrorMacro(<< "File " << this->FileName << "couldn't be written by "
203 << " the gdcm library");
204 std::cerr<<"not written \n";
210 //-----------------------------------------------------------------------------
213 //-----------------------------------------------------------------------------