1 /*=========================================================================
4 Module: $RCSfile: vtkGdcmWriter.cxx,v $
6 Date: $Date: 2005/02/25 19:54:06 $
7 Version: $Revision: 1.17 $
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 vtkCxxRevisionMacro(vtkGdcmWriter, "$Revision: 1.17 $");
31 vtkStandardNewMacro(vtkGdcmWriter);
33 //-----------------------------------------------------------------------------
34 // Constructor / Destructor
35 vtkGdcmWriter::vtkGdcmWriter()
37 this->LookupTable = NULL;
38 this->FileDimensionality = 3;
39 this->WriteType = VTK_GDCM_WRITE_TYPE_EXPLICIT_VR;
42 StudyInstanceUID = "";
43 SeriesInstanceUID = "";
44 FrameOfReferenceInstanceUID = "";
47 vtkGdcmWriter::~vtkGdcmWriter()
51 //-----------------------------------------------------------------------------
53 void vtkGdcmWriter::PrintSelf(ostream& os, vtkIndent indent)
55 this->Superclass::PrintSelf(os,indent);
57 os << indent << "Write type : " << this->GetWriteTypeAsString();
60 //-----------------------------------------------------------------------------
62 const char *vtkGdcmWriter::GetWriteTypeAsString()
66 case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
68 case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
70 case VTK_GDCM_WRITE_TYPE_ACR :
72 case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
79 void vtkGdcmWriter::SetUIDPrefix(const char *prefix)
84 const char *vtkGdcmWriter::GetUIDPrefix()
86 return UIDPrefix.c_str();
89 void vtkGdcmWriter::NewStudyInstanceUID()
91 StudyInstanceUID = "";
94 void vtkGdcmWriter::NewSeriesInstanceUID()
96 SeriesInstanceUID = "";
99 void vtkGdcmWriter::NewFrameOfReferenceInstanceUID()
101 FrameOfReferenceInstanceUID = "";
104 //-----------------------------------------------------------------------------
107 * Copy the image and reverse the Y axis
109 // The output datas must be deleted by the user of the method !!!
110 size_t ReverseData(vtkImageData *image,unsigned char **data)
113 int *extent = image->GetUpdateExtent();
114 int dim[3] = {extent[1]-extent[0]+1,
115 extent[3]-extent[2]+1,
116 extent[5]-extent[4]+1};
118 size_t lineSize = dim[0] * image->GetScalarSize()
119 * image->GetNumberOfScalarComponents();
120 size_t planeSize = dim[1] * lineSize;
121 size_t size = dim[2] * planeSize;
125 *data = new unsigned char[size];
127 image->GetIncrements(inc);
128 unsigned char *src = (unsigned char *)image->GetScalarPointerForExtent(extent);
129 unsigned char *dst = *data + planeSize - lineSize;
130 for (int plane = extent[4]; plane <= extent[5]; plane++)
132 for (int line = extent[2]; line <= extent[3]; line++)
134 // Copy one line at proper destination:
135 memcpy((void*)dst, (void*)src, lineSize);
137 src += inc[1] * image->GetScalarSize();
140 dst += 2 * planeSize;
152 * Set the datas informations in the file
154 void SetImageInformation(gdcm::FileHelper *file,vtkImageData *image)
156 std::ostringstream str;
159 int *extent = image->GetUpdateExtent();
160 int dim[3] = {extent[1]-extent[0]+1,
161 extent[3]-extent[2]+1,
162 extent[5]-extent[4]+1};
166 file->InsertValEntry(str.str(),0x0028,0x0011); // Columns
170 file->InsertValEntry(str.str(),0x0028,0x0010); // Rows
176 //file->Insert(str.str(),0x0028,0x0012); // Planes
177 file->InsertValEntry(str.str(),0x0028,0x0008); // Number of Frames
182 str << image->GetScalarSize()*8;
183 file->InsertValEntry(str.str(),0x0028,0x0100); // Bits Allocated
184 file->InsertValEntry(str.str(),0x0028,0x0101); // Bits Stored
187 str << image->GetScalarSize()*8-1;
188 file->InsertValEntry(str.str(),0x0028,0x0102); // High Bit
191 // FIXME : what do we do when the ScalarType is
192 // VTK_UNSIGNED_INT or VTK_UNSIGNED_LONG
194 if( image->GetScalarType() == VTK_UNSIGNED_CHAR ||
195 image->GetScalarType() == VTK_UNSIGNED_SHORT ||
196 image->GetScalarType() == VTK_UNSIGNED_INT ||
197 image->GetScalarType() == VTK_UNSIGNED_LONG )
199 str << "0"; // Unsigned
203 str << "1"; // Signed
205 file->InsertValEntry(str.str(),0x0028,0x0103); // Pixel Representation
209 str << image->GetNumberOfScalarComponents();
210 file->InsertValEntry(str.str(),0x0028,0x0002); // Samples per Pixel
213 double *sp = image->GetSpacing();
216 // We are about to enter floating point value. By default ostringstream are smart and don't do fixed point
217 // thus forcing to fixed point value
218 str.setf( std::ios::fixed );
219 str << sp[0] << "\\" << sp[1];
220 file->InsertValEntry(str.str(),0x0028,0x0030); // Pixel Spacing
223 file->InsertValEntry(str.str(),0x0018,0x0088); // Spacing Between Slices
226 double *org = image->GetOrigin();
229 str << org[0] << "\\" << org[1] << "\\" << org[2];
230 file->InsertValEntry(str.str(),0x0020,0x0032); // Image Position Patient
231 str.unsetf( std::ios::fixed ); //done with floating point values
234 double *rng=image->GetScalarRange();
237 str << rng[1]-rng[0];
238 file->InsertValEntry(str.str(),0x0028,0x1051); // Window Width
240 str << (rng[1]+rng[0])/2.0;
241 file->InsertValEntry(str.str(),0x0028,0x1050); // Window Center
245 size_t size = ReverseData(image,&data);
246 file->SetUserData(data,size);
251 * The call to this method is recursive if there is some files to write
253 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *image, ofstream *file)
257 vtkErrorMacro( << "File musn't be opened");
261 if( image->GetScalarType() == VTK_FLOAT ||
262 image->GetScalarType() == VTK_DOUBLE )
264 vtkErrorMacro(<< "Bad input type. Scalar type musn't be of type "
265 << "VTK_FLOAT or VTKDOUBLE (found:"
266 << image->GetScalarTypeAsString());
270 RecursiveWrite(axis,image,image,file);
271 //WriteDcmFile(this->FileName,image);
274 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *cache,
275 vtkImageData *image, ofstream *file)
279 // if the file is already open then just write to it
282 vtkErrorMacro( << "File musn't be opened");
286 // if we need to open another slice, do it
287 if( (axis + 1) == this->FileDimensionality )
289 // determine the name
292 sprintf(this->InternalFileName,"%s",this->FileName);
296 if (this->FilePrefix)
298 sprintf(this->InternalFileName, this->FilePattern,
299 this->FilePrefix, this->FileNumber);
303 sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
305 if (this->FileNumber < this->MinimumFileNumber)
307 this->MinimumFileNumber = this->FileNumber;
309 else if (this->FileNumber > this->MaximumFileNumber)
311 this->MaximumFileNumber = this->FileNumber;
316 WriteDcmFile(this->InternalFileName,image);
321 // if the current region is too high a dimension forthe file
322 // the we will split the current axis
323 cache->GetAxisUpdateExtent(axis, min, max);
325 // if it is the y axis then flip by default
326 if (axis == 1 && !this->FileLowerLeft)
328 for(idx = max; idx >= min; idx--)
330 cache->SetAxisUpdateExtent(axis, idx, idx);
331 this->RecursiveWrite(axis - 1, cache, image, file);
336 for(idx = min; idx <= max; idx++)
338 cache->SetAxisUpdateExtent(axis, idx, idx);
339 this->RecursiveWrite(axis - 1, cache, image, file);
343 // restore original extent
344 cache->SetAxisUpdateExtent(axis, min, max);
347 void vtkGdcmWriter::WriteDcmFile(char *fileName,vtkImageData *image)
349 // From here, the write of the file begins
350 gdcm::FileHelper *dcmFile = new gdcm::FileHelper();
353 if( StudyInstanceUID.empty() )
354 StudyInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
355 if( SeriesInstanceUID.empty() )
356 SeriesInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
357 if( FrameOfReferenceInstanceUID.empty() )
358 FrameOfReferenceInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
359 std::string uid = gdcm::Util::CreateUniqueUID( UIDPrefix );
361 dcmFile->InsertValEntry(uid,0x0008,0x0018); //[SOP Instance UID]
362 dcmFile->InsertValEntry(uid,0x0002,0x0003); //[Media Stored SOP Instance UID]
363 dcmFile->InsertValEntry(StudyInstanceUID,0x0020,0x000d); //[Study Instance UID]
364 dcmFile->InsertValEntry(SeriesInstanceUID,0x0020,0x000e); //[Series Instance UID]
365 dcmFile->InsertValEntry(FrameOfReferenceInstanceUID,0x0020, 0x0052); //[Frame of Reference UID]
367 // Set the image informations
368 SetImageInformation(dcmFile,image);
371 switch(this->WriteType)
373 case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
374 dcmFile->SetWriteTypeToDcmExplVR();
376 case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
377 dcmFile->SetWriteTypeToDcmImplVR();
379 case VTK_GDCM_WRITE_TYPE_ACR :
380 dcmFile->SetWriteTypeToAcr();
382 case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
383 dcmFile->SetWriteTypeToAcrLibido();
386 dcmFile->SetWriteTypeToDcmExplVR();
389 if(!dcmFile->Write(fileName))
391 vtkErrorMacro( << "File " << this->FileName << "couldn't be written by "
392 << " the gdcm library");
396 if( dcmFile->GetUserData() && dcmFile->GetUserDataSize()>0 )
398 delete[] dcmFile->GetUserData();
403 //-----------------------------------------------------------------------------
406 //-----------------------------------------------------------------------------