1 /*=========================================================================
4 Module: $RCSfile: vtkGdcmWriter.cxx,v $
6 Date: $Date: 2005/01/28 10:07:35 $
7 Version: $Revision: 1.16 $
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.16 $");
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 str << sp[0] << "\\" << sp[1];
217 file->InsertValEntry(str.str(),0x0028,0x0030); // Pixel Spacing
220 file->InsertValEntry(str.str(),0x0018,0x0088); // Spacing Between Slices
223 double *org = image->GetOrigin();
226 str << org[0] << "\\" << org[1] << "\\" << org[2];
227 file->InsertValEntry(str.str(),0x0020,0x0032); // Image Position Patient
230 double *rng=image->GetScalarRange();
233 str << rng[1]-rng[0];
234 file->InsertValEntry(str.str(),0x0028,0x1051); // Window Width
236 str << (rng[1]+rng[0])/2.0;
237 file->InsertValEntry(str.str(),0x0028,0x1050); // Window Center
241 size_t size = ReverseData(image,&data);
242 file->SetUserData(data,size);
247 * The call to this method is recursive if there is some files to write
249 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *image, ofstream *file)
253 vtkErrorMacro( << "File musn't be opened");
257 if( image->GetScalarType() == VTK_FLOAT ||
258 image->GetScalarType() == VTK_DOUBLE )
260 vtkErrorMacro(<< "Bad input type. Scalar type musn't be of type "
261 << "VTK_FLOAT or VTKDOUBLE (found:"
262 << image->GetScalarTypeAsString());
266 RecursiveWrite(axis,image,image,file);
267 //WriteDcmFile(this->FileName,image);
270 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *cache,
271 vtkImageData *image, ofstream *file)
275 // if the file is already open then just write to it
278 vtkErrorMacro( << "File musn't be opened");
282 // if we need to open another slice, do it
283 if( (axis + 1) == this->FileDimensionality )
285 // determine the name
288 sprintf(this->InternalFileName,"%s",this->FileName);
292 if (this->FilePrefix)
294 sprintf(this->InternalFileName, this->FilePattern,
295 this->FilePrefix, this->FileNumber);
299 sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
301 if (this->FileNumber < this->MinimumFileNumber)
303 this->MinimumFileNumber = this->FileNumber;
305 else if (this->FileNumber > this->MaximumFileNumber)
307 this->MaximumFileNumber = this->FileNumber;
312 WriteDcmFile(this->InternalFileName,image);
317 // if the current region is too high a dimension forthe file
318 // the we will split the current axis
319 cache->GetAxisUpdateExtent(axis, min, max);
321 // if it is the y axis then flip by default
322 if (axis == 1 && !this->FileLowerLeft)
324 for(idx = max; idx >= min; idx--)
326 cache->SetAxisUpdateExtent(axis, idx, idx);
327 this->RecursiveWrite(axis - 1, cache, image, file);
332 for(idx = min; idx <= max; idx++)
334 cache->SetAxisUpdateExtent(axis, idx, idx);
335 this->RecursiveWrite(axis - 1, cache, image, file);
339 // restore original extent
340 cache->SetAxisUpdateExtent(axis, min, max);
343 void vtkGdcmWriter::WriteDcmFile(char *fileName,vtkImageData *image)
345 // From here, the write of the file begins
346 gdcm::FileHelper *dcmFile = new gdcm::FileHelper();
349 if( StudyInstanceUID.empty() )
350 StudyInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
351 if( SeriesInstanceUID.empty() )
352 SeriesInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
353 if( FrameOfReferenceInstanceUID.empty() )
354 FrameOfReferenceInstanceUID = gdcm::Util::CreateUniqueUID( UIDPrefix );
355 std::string uid = gdcm::Util::CreateUniqueUID( UIDPrefix );
357 dcmFile->InsertValEntry(uid,0x0008,0x0018); //[SOP Instance UID]
358 dcmFile->InsertValEntry(uid,0x0002,0x0003); //[Media Stored SOP Instance UID]
359 dcmFile->InsertValEntry(StudyInstanceUID,0x0020,0x000d); //[Study Instance UID]
360 dcmFile->InsertValEntry(SeriesInstanceUID,0x0020,0x000e); //[Series Instance UID]
361 dcmFile->InsertValEntry(FrameOfReferenceInstanceUID,0x0020, 0x0052); //[Frame of Reference UID]
363 // Set the image informations
364 SetImageInformation(dcmFile,image);
367 switch(this->WriteType)
369 case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
370 dcmFile->SetWriteTypeToDcmExplVR();
372 case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
373 dcmFile->SetWriteTypeToDcmImplVR();
375 case VTK_GDCM_WRITE_TYPE_ACR :
376 dcmFile->SetWriteTypeToAcr();
378 case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
379 dcmFile->SetWriteTypeToAcrLibido();
382 dcmFile->SetWriteTypeToDcmExplVR();
385 if(!dcmFile->Write(fileName))
387 vtkErrorMacro( << "File " << this->FileName << "couldn't be written by "
388 << " the gdcm library");
392 if( dcmFile->GetUserData() && dcmFile->GetUserDataSize()>0 )
394 delete[] dcmFile->GetUserData();
399 //-----------------------------------------------------------------------------
402 //-----------------------------------------------------------------------------