]> Creatis software - gdcm.git/blobdiff - src/gdcmFileHelper.cxx
We allow now to deal with 'non standard' 64 bits 'real' values
[gdcm.git] / src / gdcmFileHelper.cxx
index 9005f118feabe1612282f3c4fdf41397838d90d1..b61faace8ed0fd7c8a1d2a4c6ba82ebd4570acd1 100644 (file)
@@ -4,8 +4,8 @@
   Module:    $RCSfile: gdcmFileHelper.cxx,v $
   Language:  C++
 
-  Date:      $Date: 2007/08/28 09:29:26 $
-  Version:   $Revision: 1.123 $
+  Date:      $Date: 2009/05/19 15:07:58 $
+  Version:   $Revision: 1.139 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
 #include "gdcmDocEntryArchive.h"
 #include "gdcmDictSet.h"
 #include "gdcmOrientation.h"
+
+
+
+#include <algorithm>  // for transform?
+
 #if defined(__BORLANDC__)
-   #include <mem.h> // for memset
+   #include <mem.h>   // for memset
+   #include <ctype.h> //for toupper
+   #include <math.h>
 #endif 
 
 #include <fstream>
 
 These lines will be moved to the document-to-be 'User's Guide'
 
-// To read an image, user needs a gdcm::File
-gdcm::File *f = new gdcm::File(fileName);
+// To read an image, user needs a GDCM_NAME_SPACE::File
+GDCM_NAME_SPACE::File *f = new GDCM_NAME_SPACE::File(fileName);
 // or (advanced) :
 // user may also decide he doesn't want to load some parts of the header
-gdcm::File *f = new gdcm::File();
+GDCM_NAME_SPACE::File *f = new GDCM_NAME_SPACE::File();
 f->SetFileName(fileName);
    f->SetLoadMode(LD_NOSEQ);               // or      
    f->SetLoadMode(LD_NOSHADOW);            // or
@@ -61,8 +67,8 @@ f->Load();
 // user can now check some values
 std::string v = f->GetEntryValue(groupNb,ElementNb);
 
-// to get the pixels, user needs a gdcm::FileHelper
-gdcm::FileHelper *fh = new gdcm::FileHelper(f);
+// to get the pixels, user needs a GDCM_NAME_SPACE::FileHelper
+GDCM_NAME_SPACE::FileHelper *fh = new GDCM_NAME_SPACE::FileHelper(f);
 
 // user may ask not to convert Palette (if any) to RGB
 uint8_t *pixels = fh->GetImageDataRaw();
@@ -71,8 +77,8 @@ int imageLength = fh->GetImageDataRawSize();
 // He can now use the pixels, create a new image, ...
 uint8_t *userPixels = ...
 
-//To re-write the image, user re-uses the gdcm::FileHelper
-gdcm::File *fh = new gdcm::FileHelper();
+//To re-write the image, user re-uses the GDCM_NAME_SPACE::FileHelper
+GDCM_NAME_SPACE::File *fh = new GDCM_NAME_SPACE::FileHelper();
 
 fh->SetTypeToRaw(); // Even if it was possible to convert Palette to RGB
                     // (WriteMode is set)
@@ -97,7 +103,6 @@ fh->Write(newFileName);      // overwrites the file, if any
 
 
 
-
 These lines will be moved to the document-to-be 'Developer's Guide'
 
 WriteMode : WMODE_RAW / WMODE_RGB
@@ -152,7 +157,7 @@ fh->Write(newFileName);
          ElementSet::WriteContent(fp, writetype);
             writes recursively all DataElements    
    RestoreWrite();
-         (moves back to the gdcm::File all the archived elements)
+         (moves back to the GDCM_NAME_SPACE::File all the archived elements)
 */
 
 
@@ -165,7 +170,7 @@ typedef std::map<uint16_t, int> GroupHT;    //  Hash Table
 // Constructor / Destructor
 /**
  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
- *        file (gdcm::File only deals with the ... header)
+ *        file (GDCM_NAME_SPACE::File only deals with the ... header)
  *        Opens (in read only and when possible) an existing file and checks
  *        for DICOM compliance. Returns NULL on failure.
  *        It will be up to the user to load the pixels into memory
@@ -211,7 +216,7 @@ FileHelper::FileHelper(File *header)
 
 /**
  * \brief canonical destructor
- * \note  If the header (gdcm::File) was created by the FileHelper constructor,
+ * \note  If the header (GDCM_NAME_SPACE::File) was created by the FileHelper constructor,
  *        it is destroyed by the FileHelper
  */
 FileHelper::~FileHelper()
@@ -236,7 +241,7 @@ FileHelper::~FileHelper()
 // Public
 
 /**
- * \brief Sets the LoadMode of the internal gdcm::File as a boolean string. 
+ * \brief Sets the LoadMode of the internal GDCM_NAME_SPACE::File as a boolean string. 
  *        NO_SEQ, NO_SHADOW, NO_SHADOWSEQ ... (nothing more, right now)
  *        WARNING : before using NO_SHADOW, be sure *all* your files
  *        contain accurate values in the 0x0000 element (if any) 
@@ -248,7 +253,7 @@ void FileHelper::SetLoadMode(int loadMode)
    GetFile()->SetLoadMode( loadMode ); 
 }
 /**
- * \brief Sets the LoadMode of the internal gdcm::File
+ * \brief Sets the LoadMode of the internal GDCM_NAME_SPACE::File
  * @param  fileName name of the file to be open  
  */
 void FileHelper::SetFileName(std::string const &fileName)
@@ -601,7 +606,7 @@ size_t FileHelper::GetRawDataSize()
 }
 
 /**
- * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
+ * \brief Access to the underlying PixelReadConverter RGBA LUT
  */
 uint8_t* FileHelper::GetLutRGBA()
 {
@@ -611,7 +616,7 @@ uint8_t* FileHelper::GetLutRGBA()
 }
 
 /**
- * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Number
+ * \brief Access to the underlying PixelReadConverter RGBA LUT Item Number
  */
 int FileHelper::GetLutItemNumber()
 {
@@ -619,7 +624,7 @@ int FileHelper::GetLutItemNumber()
 }
 
 /**
- * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Size
+ * \brief Access to the underlying PixelReadConverter RGBA LUT Item Size
  */
 int FileHelper::GetLutItemSize()
 {
@@ -728,8 +733,6 @@ bool FileHelper::Write(std::string const &fileName)
 { 
    CheckMandatoryElements(); //called once, here !
    
-   bool flag = false;
-   DocEntry *e;   
    switch(WriteType)
    {
       case ImplicitVR:
@@ -764,13 +767,13 @@ bool FileHelper::Write(std::string const &fileName)
          // was :
          //PixelWriteConverter->SetCompressJPEGUserData(
          //   inData, expectedSize, FileInternal);
- PixelWriteConverter->SetCompressJPEGUserData(
-    PixelWriteConverter->GetUserData(),
-    PixelWriteConverter->GetUserDataSize(),FileInternal);
        PixelWriteConverter->SetCompressJPEGUserData(
+                 PixelWriteConverter->GetUserData(),
+                 PixelWriteConverter->GetUserDataSize(),FileInternal);
          break;
 
       case JPEG2000:
-         /// \TODO Maybe we should consider doing the compression here !
+         /// \todo Maybe we should consider doing the compression here !
          // PixelWriteConverter->SetCompressJPEG2000UserData(inData, expectedSize, FileInternal);
 
          SetWriteFileTypeToJPEG2000();
@@ -778,7 +781,6 @@ bool FileHelper::Write(std::string const &fileName)
             PixelWriteConverter->GetUserData(),
             PixelWriteConverter->GetUserDataSize(),
             FileInternal);
          break;
    }
 
@@ -850,14 +852,14 @@ bool FileHelper::CheckWriteIntegrity()
       int numberBitsAllocated = FileInternal->GetBitsAllocated();
       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
       {
-         gdcmWarningMacro( "numberBitsAllocated changed from " 
-                          << numberBitsAllocated << " to 16 " 
+         gdcmWarningMacro( "numberBitsAllocated changed from "
+                          << numberBitsAllocated << " to 16 "
                           << " for consistency purpose" );
          numberBitsAllocated = 16;
       }
 
       size_t decSize = FileInternal->GetXSize()
-                     * FileInternal->GetYSize() 
+                     * FileInternal->GetYSize()
                      * FileInternal->GetZSize()
                      * FileInternal->GetTSize()     
                      * FileInternal->GetSamplesPerPixel()
@@ -866,23 +868,31 @@ bool FileHelper::CheckWriteIntegrity()
       if ( FileInternal->HasLUT() )
          rgbSize = decSize * 3;
 
+      size_t userDataSize = PixelWriteConverter->GetUserDataSize();
       switch(WriteMode)
       {
          case WMODE_RAW :
-            if ( decSize!=PixelWriteConverter->GetUserDataSize() )
+            if ( abs((long)(decSize-userDataSize))>1) // ignore padding zero
             {
                gdcmWarningMacro( "Data size (Raw) is incorrect. Should be " 
-                           << decSize << " / Found :" 
-                           << PixelWriteConverter->GetUserDataSize() );
+                           << decSize << "(" 
+                           << FileInternal->GetXSize() << " * "
+                           << FileInternal->GetYSize() << " * "
+                           << FileInternal->GetZSize() << " * "
+                           << FileInternal->GetTSize() << " * "   
+                           << FileInternal->GetSamplesPerPixel() << " * "
+                           << numberBitsAllocated / 8   
+                           << ") / Found :" 
+                           << userDataSize );
                return false;
             }
             break;
          case WMODE_RGB :
-            if ( rgbSize!=PixelWriteConverter->GetUserDataSize() )
+            if ( abs((long)(rgbSize-userDataSize))>1) // ignore padding zero
             {
                gdcmWarningMacro( "Data size (RGB) is incorrect. Should be " 
-                          << decSize << " / Found " 
-                          << PixelWriteConverter->GetUserDataSize() );
+                          << rgbSize << " / Found " 
+                          << userDataSize );
                return false;
             }
             break;
@@ -1316,8 +1326,9 @@ We have to deal with 4 *very* different cases :
 -4) user modified/added some tags *without processing* the pixels (anonymization...)
    UNMODIFIED_PIXELS_IMAGE
 -Probabely some more to be added.
+ --> Set it with FileHelper::SetContentType(int);
  
-gdcm::FileHelper::CheckMandatoryElements() deals automatically with these cases.
+GDCM_NAME_SPACE::FileHelper::CheckMandatoryElements() deals automatically with these cases.
 
 1)2)3)4)
 0008 0012 Instance Creation Date
@@ -1356,7 +1367,7 @@ If 'SOP Class UID' exists in the native image  ('true DICOM' image)
     --> 'Referenced SOP Instance UID' (0x0008, 0x1155)
          whose value is the original 'SOP Class UID'
 
-3) TODO : find a trick to allow user to pass to the writter the list of the Dicom images 
+3) TO DO : find a trick to allow user to pass to the writter the list of the Dicom images 
           or the Series, (or the Study ?) he used to created his image 
           (MIP, MPR, cartography image, ...)
            These info should be stored (?)
@@ -1372,7 +1383,7 @@ If 'SOP Class UID' exists in the native image  ('true DICOM' image)
 
 
 Bellow follows the full description (hope so !) of the consistency checks performed 
-by gdcm::FileHelper::CheckMandatoryElements()
+by GDCM_NAME_SPACE::FileHelper::CheckMandatoryElements()
 
 
 -->'Media Storage SOP Class UID' (0x0002,0x0002)
@@ -1506,52 +1517,75 @@ void FileHelper::CheckMandatoryElements()
 
    // --------------------- For DataSet ---------------------
 
+   // check whether 0018|0015 [CS] [Body Part Examined] value is UPPER CASE
+   //      (avoid dciodvfy to complain!)
+   DataEntry *e_0018_0015 = FileInternal->GetDataEntry(0x0018, 0x0015);  
+   if ( e_0018_0015)
+   {
+      std::string bodyPartExamined = e_0018_0015->GetString();
+      std::transform(bodyPartExamined.begin(), bodyPartExamined.end(), bodyPartExamined.begin(), 
+                    (int(*)(int)) toupper);
+      CopyMandatoryEntry(0x0018,0x0015,bodyPartExamined,"CS");       
+   }
+
    if ( ContentType != USER_OWN_IMAGE) // when it's not a user made image
    { 
-
-      gdcmDebugMacro( "USER_OWN_IMAGE (1)");
-   // If 'SOP Class UID' exists ('true DICOM' image)
+   // If 'SOP Class UID' and 'SOP Instance UID' exist ('true DICOM' image)
    // we create the 'Source Image Sequence' SeqEntry
    // to hold informations about the Source Image
-  
+      // 'SOP Instance UID' 
       DataEntry *e_0008_0016 = FileInternal->GetDataEntry(0x0008, 0x0016);
-      if ( e_0008_0016 )
+      //
+      DataEntry *e_0008_0018 = FileInternal->GetDataEntry(0x0008, 0x0018);
+      if ( e_0008_0016 && e_0008_0018)
       {
-      // Create 'Source Image Sequence' SeqEntry
-//     SeqEntry *sis = SeqEntry::New (
-//            Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) );
-      SeqEntry *sis = SeqEntry::New (0x0008, 0x2112);
-      SQItem *sqi = SQItem::New(1);
-      // (we assume 'SOP Instance UID' exists too) 
-      // create 'Referenced SOP Class UID'
-//     DataEntry *e_0008_1150 = DataEntry::New(
-//            Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1150) );
-      DataEntry *e_0008_1150 = DataEntry::New(0x0008, 0x1150, "UI");
-      e_0008_1150->SetString( e_0008_0016->GetString());
-      sqi->AddEntry(e_0008_1150);
-      e_0008_1150->Delete();
+         // Create 'Source Image Sequence' SeqEntry
+         SeqEntry *sis = SeqEntry::New (0x0008, 0x2112);
+         SQItem *sqi = SQItem::New(1);
       
-      // create 'Referenced SOP Instance UID'
-      DataEntry *e_0008_0018 = FileInternal->GetDataEntry(0x0008, 0x0018);
-//      DataEntry *e_0008_1155 = DataEntry::New(
-//            Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1155) );
-      DataEntry *e_0008_1155 = DataEntry::New(0x0008, 0x1155, "UI");
-      e_0008_1155->SetString( e_0008_0018->GetString());
-      sqi->AddEntry(e_0008_1155);
-      e_0008_1155->Delete();
-
-      sis->AddSQItem(sqi,1);
-      sqi->Delete();
-
-      // temporarily replaces any previous 'Source Image Sequence' 
-      Archive->Push(sis);
-      sis->Delete();
-      // FIXME : is 'Image Type' *really* depending on the presence of 'SOP Class UID'?
-       if ( ContentType == FILTERED_IMAGE)      
-      // the user *knows* he just modified the pixels
-      // the image is no longer an 'Original' one
-         CopyMandatoryEntry(0x0008,0x0008,"DERIVED\\PRIMARY","CS");    
+         // create 'Referenced SOP Class UID' from 'SOP Class UID'
+
+         DataEntry *e_0008_1150 = DataEntry::New(0x0008, 0x1150, "UI");
+         e_0008_1150->SetString( e_0008_0016->GetString());
+         sqi->AddEntry(e_0008_1150);
+         e_0008_1150->Delete();
+      
+         // create 'Referenced SOP Instance UID' from 'SOP Instance UID'
+        // DataEntry *e_0008_0018 = FileInternal->GetDataEntry(0x0008, 0x0018);
+         
+         DataEntry *e_0008_1155 = DataEntry::New(0x0008, 0x1155, "UI"); 
+         e_0008_1155->SetString( e_0008_0018->GetString());
+         sqi->AddEntry(e_0008_1155);
+         e_0008_1155->Delete();
+      
+         sis->AddSQItem(sqi,1);
+         sqi->Delete();
+
+         // temporarily replaces any previous 'Source Image Sequence' 
+         Archive->Push(sis);
+         sis->Delete();
+         // FIXME : is 'Image Type' *really* depending on the presence of 'SOP Class UID'?
+         
+         if ( ContentType == FILTERED_IMAGE) // the user *knows* he just modified the pixels
+         { 
+            DataEntry *e_0008_0008 = FileInternal->GetDataEntry(0x0008, 0x0008);  
+            if ( e_0008_0008)
+            {
+               std::string imageType = e_0008_0008->GetString();
+               std::string::size_type p = imageType.find("ORIGINAL");
+               if (p == 0) // image is ORIGINAL one
+               {            
+                 // the image is no longer an 'Original' one
+                 CopyMandatoryEntry(0x0008,0x0008,"DERIVED\\PRIMARY","CS");
+               }
+               // if Image Type was not ORIGINAL\..., we keep it.
+             }
+             else // 0008_0008 was missing, wee add it.
+             {
+                 CopyMandatoryEntry(0x0008,0x0008,"DERIVED\\PRIMARY","CS");             
+             }  
+         }    
       }
    }
       
@@ -1598,7 +1632,10 @@ void FileHelper::CheckMandatoryElements()
    std::ostringstream s;
    // check 'Bits Allocated' vs decent values
    int nbBitsAllocated = FileInternal->GetBitsAllocated();
-   if ( (nbBitsAllocated == 0 || nbBitsAllocated > 32)
+
+   // We allow now to deal with 'non standard' 64 bits 'real' values
+   if ( (nbBitsAllocated == 0 || nbBitsAllocated > 64) // was 32
      || ( nbBitsAllocated > 8 && nbBitsAllocated <16) )
    {
       CopyMandatoryEntry(0x0028,0x0100,"16","US");
@@ -1983,6 +2020,8 @@ void FileHelper::Initialize()
    PixelReadConverter  = new PixelReadConvert;
    PixelWriteConverter = new PixelWriteConvert;
    Archive = new DocEntryArchive( FileInternal );
+   
+   KeepOverlays = false;
 }
 
 /**
@@ -2123,7 +2162,7 @@ void FileHelper::Print(std::ostream &os, std::string const &)
 
 
 /* Probabely something to be added to use Rescale Slope/Intercept
-Have a look ,at ITK code !
+Have a look at ITK code !
 
 // Internal function to rescale pixel according to Rescale Slope/Intercept
 template<class TBuffer, class TSource>