vtkGdcmWriter.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002                                                                                 
00003   Program:   gdcm
00004   Module:    $RCSfile: vtkGdcmWriter.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2007/06/19 13:09:45 $
00007   Version:   $Revision: 1.34 $
00008                                                                                 
00009   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
00010   l'Image). All rights reserved. See Doc/License.txt or
00011   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
00012                                                                                 
00013      This software is distributed WITHOUT ANY WARRANTY; without even
00014      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00015      PURPOSE.  See the above copyright notices for more information.
00016                                                                                 
00017 =========================================================================*/
00018                                                                                 
00019 #include "gdcmFile.h"
00020 #include "gdcmFileHelper.h"
00021 #include "gdcmDebug.h"
00022 #include "gdcmUtil.h"
00023 #include "vtkGdcmWriter.h"
00024 
00025 #include <vtkObjectFactory.h>
00026 #include <vtkImageData.h>
00027 #include <vtkPointData.h>
00028 #include <vtkLookupTable.h>
00029 #if (VTK_MAJOR_VERSION >= 5)
00030 #include <vtkMedicalImageProperties.h>
00031 #endif
00032 #ifndef vtkFloatingPointType
00033 #define vtkFloatingPointType float
00034 #endif
00035 
00036 vtkCxxRevisionMacro(vtkGdcmWriter, "$Revision: 1.34 $")
00037 vtkStandardNewMacro(vtkGdcmWriter)
00038 
00039 vtkCxxSetObjectMacro(vtkGdcmWriter,LookupTable,vtkLookupTable);
00040 #if (VTK_MAJOR_VERSION >= 5)
00041 vtkCxxSetObjectMacro(vtkGdcmWriter,MedicalImageProperties,vtkMedicalImageProperties);
00042 #endif
00043 //-----------------------------------------------------------------------------
00044 // Constructor / Destructor
00045 vtkGdcmWriter::vtkGdcmWriter()
00046 {
00047    this->LookupTable = NULL;
00048    this->MedicalImageProperties = NULL;
00049    this->FileDimensionality = 3;
00050    this->WriteType = VTK_GDCM_WRITE_TYPE_EXPLICIT_VR;
00051    this->GdcmFile = 0;
00052    this->ContentType = VTK_GDCM_WRITE_TYPE_USER_OWN_IMAGE;
00053 }
00054 
00055 vtkGdcmWriter::~vtkGdcmWriter()
00056 {
00057    this->SetMedicalImageProperties(NULL);
00058    this->SetLookupTable(NULL);
00059 }
00060 
00061 //-----------------------------------------------------------------------------
00062 // Print
00063 void vtkGdcmWriter::PrintSelf(ostream &os, vtkIndent indent)
00064 {
00065    this->Superclass::PrintSelf(os, indent);
00066 
00067    os << indent << "Write type : " << this->GetWriteTypeAsString();
00068 }
00069 
00070 //-----------------------------------------------------------------------------
00071 // Public
00072 const char *vtkGdcmWriter::GetWriteTypeAsString()
00073 {
00074    switch(WriteType)
00075    {
00076       case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
00077          return "Explicit VR";
00078       case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
00079          return "Implicit VR";
00080       case VTK_GDCM_WRITE_TYPE_ACR :
00081          return "ACR";
00082       case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
00083          return "ACR Libido";
00084       default :
00085          return "Unknow type";
00086    }
00087 }
00088 
00089 //-----------------------------------------------------------------------------
00090 // Protected
00094 // The output data must be deleted by the user of the method !!!
00095 size_t ReverseData(vtkImageData *image,unsigned char **data)
00096 {
00097 #if (VTK_MAJOR_VERSION >= 5)
00098    vtkIdType inc[3];
00099 #else
00100    int inc[3];
00101 #endif
00102    int *extent = image->GetUpdateExtent();
00103    int dim[3] = {extent[1]-extent[0]+1,
00104                  extent[3]-extent[2]+1,
00105                  extent[5]-extent[4]+1};
00106 
00107    size_t lineSize = dim[0] * image->GetScalarSize()
00108                    * image->GetNumberOfScalarComponents();
00109    size_t planeSize = dim[1] * lineSize;
00110    size_t size = dim[2] * planeSize;
00111 
00112    if( size>0 )
00113    {
00114       *data = new unsigned char[size];
00115 
00116       image->GetIncrements(inc);
00117       unsigned char *src = (unsigned char *)image->GetScalarPointerForExtent(extent);
00118       unsigned char *dst = *data + planeSize - lineSize;
00119       for (int plane = extent[4]; plane <= extent[5]; plane++)
00120       {
00121          for (int line = extent[2]; line <= extent[3]; line++)
00122          {
00123             // Copy one line at proper destination:
00124             memcpy((void*)dst, (void*)src, lineSize);
00125 
00126             src += inc[1] * image->GetScalarSize();
00127             dst -= lineSize;
00128          }
00129          dst += 2 * planeSize;
00130       }
00131    }
00132    else
00133    {
00134       *data = NULL;
00135    }
00136 
00137    return size;
00138 }
00139 
00144 #if (VTK_MAJOR_VERSION >= 5)
00145 void SetMedicalImageInformation(GDCM_NAME_SPACE::FileHelper *file, vtkMedicalImageProperties *medprop)
00146 {
00147    // For now only do:
00148    // PatientName, PatientID, PatientAge, PatientSex, PatientBirthDate, StudyID
00149    std::ostringstream str;
00150    if( medprop )
00151      {
00152      if (medprop->GetPatientName())
00153         {
00154         str.str("");
00155         str << medprop->GetPatientName();
00156         file->InsertEntryString(str.str(),0x0010,0x0010,"PN"); // PN 1 Patient's Name
00157         }
00158 
00159      if (medprop->GetPatientID())
00160         {
00161         str.str("");
00162         str << medprop->GetPatientID();
00163         file->InsertEntryString(str.str(),0x0010,0x0020,"LO"); // LO 1 Patient ID
00164         }
00165 
00166      if (medprop->GetPatientAge())
00167         {
00168         str.str("");
00169         str << medprop->GetPatientAge();
00170         file->InsertEntryString(str.str(),0x0010,0x1010,"AS"); // AS 1 Patient's Age
00171         }
00172 
00173      if (medprop->GetPatientSex())
00174         {
00175         str.str("");
00176         str << medprop->GetPatientSex();
00177         file->InsertEntryString(str.str(),0x0010,0x0040,"CS"); // CS 1 Patient's Sex
00178         }
00179 
00180      if (medprop->GetPatientBirthDate())
00181         {
00182         str.str("");
00183         str << medprop->GetPatientBirthDate();
00184         file->InsertEntryString(str.str(),0x0010,0x0030,"DA"); // DA 1 Patient's Birth Date
00185         }
00186 
00187      if (medprop->GetStudyID())
00188         {
00189         str.str("");
00190         str << medprop->GetStudyID();
00191         file->InsertEntryString(str.str(),0x0020,0x0010,"SH"); // SH 1 Study ID
00192         }
00193      }
00194 }
00195 #endif
00196 
00200 void SetImageInformation(GDCM_NAME_SPACE::FileHelper *file, vtkImageData *image)
00201 {
00202    std::ostringstream str;
00203 
00204    // Image size
00205    int *extent = image->GetUpdateExtent();
00206    int dim[3] = {extent[1]-extent[0]+1,
00207                  extent[3]-extent[2]+1,
00208                  extent[5]-extent[4]+1};
00209 
00210    str.str("");
00211    str << dim[0];
00212    file->InsertEntryString(str.str(),0x0028,0x0011,"US"); // Columns
00213 
00214    str.str("");
00215    str << dim[1];
00216    file->InsertEntryString(str.str(),0x0028,0x0010,"US"); // Rows
00217 
00218    if(dim[2]>1)
00219    {
00220       str.str("");
00221       str << dim[2];
00222       //file->Insert(str.str(),0x0028,0x0012); // Planes
00223       file->InsertEntryString(str.str(),0x0028,0x0008,"US"); // Number of Frames
00224    }
00225 
00226    // Pixel type
00227    str.str("");
00228    str << image->GetScalarSize()*8;
00229    file->InsertEntryString(str.str(),0x0028,0x0100,"US"); // Bits Allocated
00230    file->InsertEntryString(str.str(),0x0028,0x0101,"US"); // Bits Stored
00231 
00232    str.str("");
00233    str << image->GetScalarSize()*8-1;
00234    file->InsertEntryString(str.str(),0x0028,0x0102,"US"); // High Bit
00235 
00236    // Pixel Repr
00237    // FIXME : what do we do when the ScalarType is 
00238    // VTK_UNSIGNED_INT or VTK_UNSIGNED_LONG
00239    str.str("");
00240    if( image->GetScalarType() == VTK_UNSIGNED_CHAR  ||
00241        image->GetScalarType() == VTK_UNSIGNED_SHORT ||
00242        image->GetScalarType() == VTK_UNSIGNED_INT   ||
00243        image->GetScalarType() == VTK_UNSIGNED_LONG )
00244    {
00245       str << "0"; // Unsigned
00246    }
00247    else
00248    {
00249       str << "1"; // Signed
00250    }
00251    file->InsertEntryString(str.str(),0x0028,0x0103,"US"); // Pixel Representation
00252 
00253    // Samples per pixel
00254    str.str("");
00255    str << image->GetNumberOfScalarComponents();
00256    file->InsertEntryString(str.str(),0x0028,0x0002,"US"); // Samples per Pixel
00257 
00260 
00261    // Spacing
00262    vtkFloatingPointType *sp = image->GetSpacing();
00263 
00264    str.str("");
00265    // We are about to enter floating point value. 
00266    // By default ostringstream are smart and don't do fixed point
00267    // thus forcing to fixed point value
00268    str.setf( std::ios::fixed );
00269    str << sp[1] << "\\" << sp[0];
00270    file->InsertEntryString(str.str(),0x0028,0x0030,"DS"); // Pixel Spacing
00271    str.str("");
00272    str << sp[2];
00273    file->InsertEntryString(str.str(),0x0018,0x0088,"DS"); // Spacing Between Slices
00274 
00275    // Origin
00276    vtkFloatingPointType *org = image->GetOrigin();
00277 
00280 
00281    str.str("");
00282    str << org[0] << "\\" << org[1] << "\\" << org[2];
00283    file->InsertEntryString(str.str(),0x0020,0x0032,"DS"); // Image Position Patient
00284    str.unsetf( std::ios::fixed ); //done with floating point values
00285 
00286    // Window / Level
00287    vtkFloatingPointType *rng = image->GetScalarRange();
00288 
00289    str.str("");
00290    str << rng[1]-rng[0];
00291    file->InsertEntryString(str.str(),0x0028,0x1051,"DS"); // Window Width
00292    str.str("");
00293    str << (rng[1]+rng[0])/2.0;
00294    file->InsertEntryString(str.str(),0x0028,0x1050,"DS"); // Window Center
00295 
00296    // Pixels
00297    unsigned char *data;
00298    size_t size = ReverseData(image,&data);
00299    file->SetUserData(data,size);
00300 }
00301 
00306 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *image, 
00307                     ofstream *file)
00308 {
00309    if(file)
00310    {
00311       vtkErrorMacro( <<  "File must not be open");
00312       return;
00313    }
00314 
00315    if( image->GetScalarType() == VTK_FLOAT || 
00316        image->GetScalarType() == VTK_DOUBLE )
00317    {
00318       vtkErrorMacro(<< "Bad input type. Scalar type must not be of type "
00319                     << "VTK_FLOAT or VTK_DOUBLE (found:"
00320                     << image->GetScalarTypeAsString() << ")" );
00321       return;
00322    }
00323 
00324    RecursiveWrite(axis,image, image, file);
00325    //WriteDcmFile(this->FileName,image);
00326 }
00327 
00328 void vtkGdcmWriter::RecursiveWrite(int axis, vtkImageData *cache, 
00329                                    vtkImageData *image, ofstream *file)
00330 {
00331    int idx, min, max;
00332 
00333    // if the file is already open then just write to it
00334    if( file )
00335    {
00336       vtkErrorMacro( <<  "File musn't be open");
00337       return;
00338    }
00339 
00340    // if we need to open another slice, do it
00341    if( (axis + 1) == this->FileDimensionality )
00342    {
00343       // determine the name
00344       if (this->FileName)
00345       {
00346          sprintf(this->InternalFileName, "%s", this->FileName);
00347       }
00348       else 
00349       {
00350          if (this->FilePrefix)
00351          {
00352             sprintf(this->InternalFileName, this->FilePattern, 
00353             this->FilePrefix, this->FileNumber);
00354          }
00355          else
00356          {
00357             sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
00358          }
00359 // Remove this code in case user is using VTK 4.2...
00360 #if !(VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION == 2)
00361          if (this->FileNumber < this->MinimumFileNumber)
00362          {
00363             this->MinimumFileNumber = this->FileNumber;
00364          }
00365          else if (this->FileNumber > this->MaximumFileNumber)
00366          {
00367             this->MaximumFileNumber = this->FileNumber;
00368          }
00369 #endif
00370       }
00371 
00372       // Write the file
00373       WriteDcmFile(this->InternalFileName,image);
00374       ++this->FileNumber;
00375       return;
00376    }
00377 
00378    // if the current region is too high a dimension for the file
00379    // the we will split the current axis
00380    cache->GetAxisUpdateExtent(axis, min, max);
00381 
00382    // if it is the y axis then flip by default
00383    if (axis == 1 && !this->FileLowerLeft)
00384    {
00385       for(idx = max; idx >= min; idx--)
00386       {
00387          cache->SetAxisUpdateExtent(axis, idx, idx);
00388          this->RecursiveWrite(axis - 1, cache, image, file);
00389       }
00390    }
00391    else
00392    {
00393       for(idx = min; idx <= max; idx++)
00394       {
00395          cache->SetAxisUpdateExtent(axis, idx, idx);
00396          this->RecursiveWrite(axis - 1, cache, image, file);
00397       }
00398    }
00399 
00400    // restore original extent
00401    cache->SetAxisUpdateExtent(axis, min, max);
00402 }
00403 
00404 void vtkGdcmWriter::WriteDcmFile(char *fileName, vtkImageData *image)
00405 {
00406    GDCM_NAME_SPACE::FileHelper *dcmFile;
00407    if ( GdcmFile != 0)
00408       dcmFile = GDCM_NAME_SPACE::FileHelper::New(GdcmFile);
00409    else
00410       dcmFile = GDCM_NAME_SPACE::FileHelper::New();
00411    
00412    // From here, the write of the file begins
00413 
00414    // Set the medical informations:
00415 #if (VTK_MAJOR_VERSION >= 5)  
00416    SetMedicalImageInformation(dcmFile, this->MedicalImageProperties);
00417 #endif
00418       
00419    // Set the image informations
00420    SetImageInformation(dcmFile, image);
00421 
00422    // Write the image
00423    switch(this->WriteType)
00424    {
00425       case VTK_GDCM_WRITE_TYPE_EXPLICIT_VR :
00426          dcmFile->SetWriteTypeToDcmExplVR();
00427          break;
00428       case VTK_GDCM_WRITE_TYPE_IMPLICIT_VR :
00429          dcmFile->SetWriteTypeToDcmImplVR();
00430          break;
00431       case VTK_GDCM_WRITE_TYPE_ACR :
00432          dcmFile->SetWriteTypeToAcr();
00433          break;
00434       case VTK_GDCM_WRITE_TYPE_ACR_LIBIDO :
00435          dcmFile->SetWriteTypeToAcrLibido();
00436          break;
00437       default :
00438          dcmFile->SetWriteTypeToDcmExplVR();
00439    }
00440   
00441    dcmFile->SetContentType((GDCM_NAME_SPACE::ImageContentType)ContentType);
00442  
00443    if(!dcmFile->Write(fileName))
00444    {
00445       vtkErrorMacro( << "File "  <<  this->FileName  <<  "cannot be written by "
00446                      << " the gdcm library");
00447    }
00448    // Clean up
00449    if( dcmFile->GetUserData() && dcmFile->GetUserDataSize()>0 )
00450    {
00451       delete[] dcmFile->GetUserData();
00452    }
00453    dcmFile->Delete();
00454 }
00455 
00456 //-----------------------------------------------------------------------------
00457 // Private
00458 
00459 //-----------------------------------------------------------------------------

Generated on Fri Aug 24 12:59:32 2007 for gdcm by  doxygen 1.4.6