1 /*=========================================================================
4 Module: $RCSfile: vtkGdcmWriter.cxx,v $
6 Date: $Date: 2006/03/17 14:46:18 $
7 Version: $Revision: 1.27 $
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.
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.
17 =========================================================================*/
20 #include "gdcmFileHelper.h"
21 #include "gdcmDebug.h"
23 #include "vtkGdcmWriter.h"
25 #include <vtkObjectFactory.h>
26 #include <vtkImageData.h>
27 #include <vtkPointData.h>
28 #include <vtkLookupTable.h>
30 #ifndef vtkFloatingPointType
31 #define vtkFloatingPointType float
34 vtkCxxRevisionMacro(vtkGdcmWriter, "$Revision: 1.27 $")
35 vtkStandardNewMacro(vtkGdcmWriter)
37 //-----------------------------------------------------------------------------
38 // Constructor / Destructor
39 vtkGdcmWriter::vtkGdcmWriter()
41 this->LookupTable = NULL;
42 this->FileDimensionality = 3;
43 this->WriteType = VTK_GDCM_WRITE_TYPE_EXPLICIT_VR;
45 this->ContentType = VTK_GDCM_WRITE_TYPE_USER_OWN_IMAGE;
48 vtkGdcmWriter::~vtkGdcmWriter()
52 //-----------------------------------------------------------------------------
54 void vtkGdcmWriter::PrintSelf(ostream &os, vtkIndent indent)
56 this->Superclass::PrintSelf(os, indent);
58 os << indent << "Write type : " << this->GetWriteTypeAsString();
61 //-----------------------------------------------------------------------------
63 const char *vtkGdcmWriter::GetWriteTypeAsString()
67 case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
69 case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
71 case VTK_GDCM_WRITE_TYPE_ACR :
73 case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
80 //-----------------------------------------------------------------------------
83 * Copy the image and reverse the Y axis
85 // The output data must be deleted by the user of the method !!!
86 size_t ReverseData(vtkImageData *image,unsigned char **data)
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};
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;
101 *data = new unsigned char[size];
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++)
108 for (int line = extent[2]; line <= extent[3]; line++)
110 // Copy one line at proper destination:
111 memcpy((void*)dst, (void*)src, lineSize);
113 src += inc[1] * image->GetScalarSize();
116 dst += 2 * planeSize;
128 * Set the data informations in the file
130 void SetImageInformation(gdcm::FileHelper *file, vtkImageData *image)
132 std::ostringstream str;
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};
142 file->InsertEntryString(str.str(),0x0028,0x0011); // Columns
146 file->InsertEntryString(str.str(),0x0028,0x0010); // Rows
152 //file->Insert(str.str(),0x0028,0x0012); // Planes
153 file->InsertEntryString(str.str(),0x0028,0x0008); // Number of Frames
158 str << image->GetScalarSize()*8;
159 file->InsertEntryString(str.str(),0x0028,0x0100); // Bits Allocated
160 file->InsertEntryString(str.str(),0x0028,0x0101); // Bits Stored
163 str << image->GetScalarSize()*8-1;
164 file->InsertEntryString(str.str(),0x0028,0x0102); // High Bit
167 // FIXME : what do we do when the ScalarType is
168 // VTK_UNSIGNED_INT or VTK_UNSIGNED_LONG
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 )
175 str << "0"; // Unsigned
179 str << "1"; // Signed
181 file->InsertEntryString(str.str(),0x0028,0x0103); // Pixel Representation
185 str << image->GetNumberOfScalarComponents();
186 file->InsertEntryString(str.str(),0x0028,0x0002); // Samples per Pixel
188 /// \todo : Spacing Between Slices is meaningfull ONLY for CT an MR modality
189 /// We should perform some checkings before forcing the Entry creation
192 vtkFloatingPointType *sp = image->GetSpacing();
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
203 file->InsertEntryString(str.str(),0x0018,0x0088); // Spacing Between Slices
206 vtkFloatingPointType *org = image->GetOrigin();
208 /// \todo : Image Position Patient is meaningfull ONLY for CT an MR modality
209 /// We should perform some checkings before forcing the Entry creation
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
217 vtkFloatingPointType *rng = image->GetScalarRange();
220 str << rng[1]-rng[0];
221 file->InsertEntryString(str.str(),0x0028,0x1051); // Window Width
223 str << (rng[1]+rng[0])/2.0;
224 file->InsertEntryString(str.str(),0x0028,0x1050); // Window Center
228 size_t size = ReverseData(image,&data);
229 file->SetUserData(data,size);
234 * The call to this method is recursive if there is some files to write
236 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *image,
241 vtkErrorMacro( << "File must not be open");
245 if( image->GetScalarType() == VTK_FLOAT ||
246 image->GetScalarType() == VTK_DOUBLE )
248 vtkErrorMacro(<< "Bad input type. Scalar type must not be of type "
249 << "VTK_FLOAT or VTK_DOUBLE (found:"
250 << image->GetScalarTypeAsString() << ")" );
254 RecursiveWrite(axis,image, image, file);
255 //WriteDcmFile(this->FileName,image);
258 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *cache,
259 vtkImageData *image, ofstream *file)
263 // if the file is already open then just write to it
266 vtkErrorMacro( << "File musn't be open");
270 // if we need to open another slice, do it
271 if( (axis + 1) == this->FileDimensionality )
273 // determine the name
276 sprintf(this->InternalFileName, "%s", this->FileName);
280 if (this->FilePrefix)
282 sprintf(this->InternalFileName, this->FilePattern,
283 this->FilePrefix, this->FileNumber);
287 sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
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)
293 this->MinimumFileNumber = this->FileNumber;
295 else if (this->FileNumber > this->MaximumFileNumber)
297 this->MaximumFileNumber = this->FileNumber;
303 WriteDcmFile(this->InternalFileName,image);
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);
312 // if it is the y axis then flip by default
313 if (axis == 1 && !this->FileLowerLeft)
315 for(idx = max; idx >= min; idx--)
317 cache->SetAxisUpdateExtent(axis, idx, idx);
318 this->RecursiveWrite(axis - 1, cache, image, file);
323 for(idx = min; idx <= max; idx++)
325 cache->SetAxisUpdateExtent(axis, idx, idx);
326 this->RecursiveWrite(axis - 1, cache, image, file);
330 // restore original extent
331 cache->SetAxisUpdateExtent(axis, min, max);
334 void vtkGdcmWriter::WriteDcmFile(char *fileName, vtkImageData *image)
336 gdcm::FileHelper *dcmFile;
338 dcmFile = gdcm::FileHelper::New(GdcmFile);
340 dcmFile = gdcm::FileHelper::New();
342 // From here, the write of the file begins
344 // Set the image informations
345 SetImageInformation(dcmFile, image);
348 switch(this->WriteType)
350 case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
351 dcmFile->SetWriteTypeToDcmExplVR();
353 case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
354 dcmFile->SetWriteTypeToDcmImplVR();
356 case VTK_GDCM_WRITE_TYPE_ACR :
357 dcmFile->SetWriteTypeToAcr();
359 case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
360 dcmFile->SetWriteTypeToAcrLibido();
363 dcmFile->SetWriteTypeToDcmExplVR();
366 if(!dcmFile->Write(fileName))
368 vtkErrorMacro( << "File " << this->FileName << "cannot be written by "
369 << " the gdcm library");
373 if( dcmFile->GetUserData() && dcmFile->GetUserDataSize()>0 )
375 delete[] dcmFile->GetUserData();
380 //-----------------------------------------------------------------------------
383 //-----------------------------------------------------------------------------