1 /*=========================================================================
4 Module: $RCSfile: vtkGdcmWriter.cxx,v $
6 Date: $Date: 2007/12/13 15:16:19 $
7 Version: $Revision: 1.36 $
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>
29 #if (VTK_MAJOR_VERSION >= 5)
30 #include <vtkMedicalImageProperties.h>
32 #ifndef vtkFloatingPointType
33 #define vtkFloatingPointType float
36 vtkCxxRevisionMacro(vtkGdcmWriter, "$Revision: 1.36 $")
37 vtkStandardNewMacro(vtkGdcmWriter)
39 vtkCxxSetObjectMacro(vtkGdcmWriter,LookupTable,vtkLookupTable)
40 #if (VTK_MAJOR_VERSION >= 5)
41 vtkCxxSetObjectMacro(vtkGdcmWriter,MedicalImageProperties,vtkMedicalImageProperties)
43 //-----------------------------------------------------------------------------
44 // Constructor / Destructor
45 vtkGdcmWriter::vtkGdcmWriter()
47 this->LookupTable = NULL;
48 this->MedicalImageProperties = NULL;
49 this->FileDimensionality = 3;
50 this->WriteType = VTK_GDCM_WRITE_TYPE_EXPLICIT_VR;
52 this->ContentType = VTK_GDCM_WRITE_TYPE_USER_OWN_IMAGE;
55 vtkGdcmWriter::~vtkGdcmWriter()
57 this->SetMedicalImageProperties(NULL);
58 this->SetLookupTable(NULL);
61 //-----------------------------------------------------------------------------
63 void vtkGdcmWriter::PrintSelf(ostream &os, vtkIndent indent)
65 this->Superclass::PrintSelf(os, indent);
67 os << indent << "Write type : " << this->GetWriteTypeAsString();
70 //-----------------------------------------------------------------------------
72 const char *vtkGdcmWriter::GetWriteTypeAsString()
76 case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
78 case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
80 case VTK_GDCM_WRITE_TYPE_ACR :
82 case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
89 //-----------------------------------------------------------------------------
92 * Copy the image and reverse the Y axis
94 // The output data must be deleted by the user of the method !!!
95 size_t ReverseData(vtkImageData *image,unsigned char **data)
97 #if (VTK_MAJOR_VERSION >= 5)
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};
107 size_t lineSize = dim[0] * image->GetScalarSize()
108 * image->GetNumberOfScalarComponents();
109 size_t planeSize = dim[1] * lineSize;
110 size_t size = dim[2] * planeSize;
114 *data = new unsigned char[size];
116 image->GetIncrements(inc);
117 unsigned char *src = (unsigned char *)image->GetScalarPointerForExtent(extent);
118 unsigned char *dst = *data + planeSize - lineSize;
119 for (int plane = extent[4]; plane <= extent[5]; plane++)
121 for (int line = extent[2]; line <= extent[3]; line++)
123 // Copy one line at proper destination:
124 memcpy((void*)dst, (void*)src, lineSize);
126 src += inc[1] * image->GetScalarSize();
129 dst += 2 * planeSize;
141 * Set the medical informations in the file, based on the user passed
142 * vtkMedicalImageProperties
144 #if (VTK_MAJOR_VERSION >= 5)
145 void SetMedicalImageInformation(GDCM_NAME_SPACE::FileHelper *file, vtkMedicalImageProperties *medprop)
148 // PatientName, PatientID, PatientAge, PatientSex, PatientBirthDate, StudyID
149 std::ostringstream str;
152 if (medprop->GetPatientName())
155 str << medprop->GetPatientName();
156 file->InsertEntryString(str.str(),0x0010,0x0010,"PN"); // PN 1 Patient's Name
159 if (medprop->GetPatientID())
162 str << medprop->GetPatientID();
163 file->InsertEntryString(str.str(),0x0010,0x0020,"LO"); // LO 1 Patient ID
166 if (medprop->GetPatientAge())
169 str << medprop->GetPatientAge();
170 file->InsertEntryString(str.str(),0x0010,0x1010,"AS"); // AS 1 Patient's Age
173 if (medprop->GetPatientSex())
176 str << medprop->GetPatientSex();
177 file->InsertEntryString(str.str(),0x0010,0x0040,"CS"); // CS 1 Patient's Sex
180 if (medprop->GetPatientBirthDate())
183 str << medprop->GetPatientBirthDate();
184 file->InsertEntryString(str.str(),0x0010,0x0030,"DA"); // DA 1 Patient's Birth Date
187 if (medprop->GetStudyID())
190 str << medprop->GetStudyID();
191 file->InsertEntryString(str.str(),0x0020,0x0010,"SH"); // SH 1 Study ID
198 * Set the data informations in the file
200 void SetImageInformation(GDCM_NAME_SPACE::FileHelper *file, vtkImageData *image)
202 std::ostringstream str;
205 int *extent = image->GetUpdateExtent();
206 int dim[3] = {extent[1]-extent[0]+1,
207 extent[3]-extent[2]+1,
208 extent[5]-extent[4]+1};
212 file->InsertEntryString(str.str(),0x0028,0x0011,"US"); // Columns
216 file->InsertEntryString(str.str(),0x0028,0x0010,"US"); // Rows
222 //file->Insert(str.str(),0x0028,0x0012); // Planes
223 file->InsertEntryString(str.str(),0x0028,0x0008,"IS"); // Number of Frames
228 str << image->GetScalarSize()*8;
229 file->InsertEntryString(str.str(),0x0028,0x0100,"US"); // Bits Allocated
230 file->InsertEntryString(str.str(),0x0028,0x0101,"US"); // Bits Stored
233 str << image->GetScalarSize()*8-1;
234 file->InsertEntryString(str.str(),0x0028,0x0102,"US"); // High Bit
237 // FIXME : what do we do when the ScalarType is
238 // VTK_UNSIGNED_INT or VTK_UNSIGNED_LONG
240 if( image->GetScalarType() == VTK_UNSIGNED_CHAR ||
241 image->GetScalarType() == VTK_UNSIGNED_SHORT ||
242 image->GetScalarType() == VTK_UNSIGNED_INT ||
243 image->GetScalarType() == VTK_UNSIGNED_LONG )
245 str << "0"; // Unsigned
249 str << "1"; // Signed
251 file->InsertEntryString(str.str(),0x0028,0x0103,"US"); // Pixel Representation
255 str << image->GetNumberOfScalarComponents();
256 file->InsertEntryString(str.str(),0x0028,0x0002,"US"); // Samples per Pixel
258 /// \todo : Spacing Between Slices is meaningfull ONLY for CT an MR modality
259 /// We should perform some checkings before forcing the Entry creation
262 vtkFloatingPointType *sp = image->GetSpacing();
265 // We are about to enter floating point value.
266 // By default ostringstream are smart and don't do fixed point
267 // thus forcing to fixed point value
268 str.setf( std::ios::fixed );
269 str << sp[1] << "\\" << sp[0];
270 file->InsertEntryString(str.str(),0x0028,0x0030,"DS"); // Pixel Spacing
273 file->InsertEntryString(str.str(),0x0018,0x0088,"DS"); // Spacing Between Slices
276 vtkFloatingPointType *org = image->GetOrigin();
278 /// \todo : Image Position Patient is meaningfull ONLY for CT an MR modality
279 /// We should perform some checkings before forcing the Entry creation
282 str << org[0] << "\\" << org[1] << "\\" << org[2];
283 file->InsertEntryString(str.str(),0x0020,0x0032,"DS"); // Image Position Patient
284 str.unsetf( std::ios::fixed ); //done with floating point values
287 vtkFloatingPointType *rng = image->GetScalarRange();
290 str << rng[1]-rng[0];
291 file->InsertEntryString(str.str(),0x0028,0x1051,"DS"); // Window Width
293 str << (rng[1]+rng[0])/2.0;
294 file->InsertEntryString(str.str(),0x0028,0x1050,"DS"); // Window Center
298 size_t size = ReverseData(image,&data);
299 file->SetUserData(data,size);
304 * The call to this method is recursive if there is some files to write
306 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *image,
311 vtkErrorMacro( << "File must not be open");
315 if( image->GetScalarType() == VTK_FLOAT ||
316 image->GetScalarType() == VTK_DOUBLE )
318 vtkErrorMacro(<< "Bad input type. Scalar type must not be of type "
319 << "VTK_FLOAT or VTK_DOUBLE (found:"
320 << image->GetScalarTypeAsString() << ")" );
324 RecursiveWrite(axis,image, image, file);
325 //WriteDcmFile(this->FileName,image);
328 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *cache,
329 vtkImageData *image, ofstream *file)
333 // if the file is already open then just write to it
336 vtkErrorMacro( << "File musn't be open");
340 // if we need to open another slice, do it
341 if( (axis + 1) == this->FileDimensionality )
343 // determine the name
346 sprintf(this->InternalFileName, "%s", this->FileName);
350 if (this->FilePrefix)
352 sprintf(this->InternalFileName, this->FilePattern,
353 this->FilePrefix, this->FileNumber);
357 sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
359 // Remove this code in case user is using VTK 4.2...
360 #if !(VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION == 2)
361 if (this->FileNumber < this->MinimumFileNumber)
363 this->MinimumFileNumber = this->FileNumber;
365 else if (this->FileNumber > this->MaximumFileNumber)
367 this->MaximumFileNumber = this->FileNumber;
373 WriteDcmFile(this->InternalFileName,image);
378 // if the current region is too high a dimension for the file
379 // the we will split the current axis
380 cache->GetAxisUpdateExtent(axis, min, max);
382 // if it is the y axis then flip by default
383 if (axis == 1 && !this->FileLowerLeft)
385 for(idx = max; idx >= min; idx--)
387 cache->SetAxisUpdateExtent(axis, idx, idx);
388 this->RecursiveWrite(axis - 1, cache, image, file);
393 for(idx = min; idx <= max; idx++)
395 cache->SetAxisUpdateExtent(axis, idx, idx);
396 this->RecursiveWrite(axis - 1, cache, image, file);
400 // restore original extent
401 cache->SetAxisUpdateExtent(axis, min, max);
404 void vtkGdcmWriter::WriteDcmFile(char *fileName, vtkImageData *image)
406 GDCM_NAME_SPACE::FileHelper *dcmFile;
408 dcmFile = GDCM_NAME_SPACE::FileHelper::New(GdcmFile);
410 dcmFile = GDCM_NAME_SPACE::FileHelper::New();
412 // From here, the write of the file begins
414 // Set the medical informations:
415 #if (VTK_MAJOR_VERSION >= 5)
416 SetMedicalImageInformation(dcmFile, this->MedicalImageProperties);
419 // Set the image informations
420 SetImageInformation(dcmFile, image);
423 switch(this->WriteType)
425 case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
426 dcmFile->SetWriteTypeToDcmExplVR();
428 case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
429 dcmFile->SetWriteTypeToDcmImplVR();
431 case VTK_GDCM_WRITE_TYPE_ACR :
432 dcmFile->SetWriteTypeToAcr();
434 case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
435 dcmFile->SetWriteTypeToAcrLibido();
438 dcmFile->SetWriteTypeToDcmExplVR();
441 dcmFile->SetContentType((GDCM_NAME_SPACE::ImageContentType)ContentType);
443 if(!dcmFile->Write(fileName))
445 vtkErrorMacro( << "File " << this->FileName << "cannot be written by "
446 << " the gdcm library");
449 if( dcmFile->GetUserData() && dcmFile->GetUserDataSize()>0 )
451 delete[] dcmFile->GetUserData();
456 //-----------------------------------------------------------------------------
459 //-----------------------------------------------------------------------------