]> Creatis software - gdcm.git/commitdiff
* In order to fix writing of dicom files:
authorfrog <frog>
Fri, 18 Jun 2004 12:26:53 +0000 (12:26 +0000)
committerfrog <frog>
Fri, 18 Jun 2004 12:26:53 +0000 (12:26 +0000)
     - Test/TestWriteSimple.cxx: a simpler example of writing.
     - Test/CMakeLists.txt changed accordingly.
     - src/gdcmDocument.cxx:
       -- The destructor now recursilvely removes potential sequences.
       -- Bug fix in ::IsJPEG2000()
       -- ::ReplaceOrCreateByNumber(std::string, guint16, guint16)
          now handles promotion of gdcmDocEntry to gdcmValEntry in a cleaner
          manner.
       -- ::GetValEntryByNumber(guint16, guint16) now defined (as opposed
          to only declared) and build on top of
          ::GetDocEntryByNumber(guint16, guint16).
       -- ::SetEntryByNumber() now uses GetValEntryByNumber(group, element)
     - src/gdcmElementSet.[h|cxx]: added ::RemoveEntry(gdcmDocEntry *)
       for usage in destructor and treatement of promotion in
       ::ReplaceOrCreateByNumber().
     - src/gdcmSQItem.cxx: destructor should better handle his job.
      Test/TestWriteSimple now runs (or at least it DOES something).
    * We can now start hutting memory links. A good starting point is:
      valgrind -q --skin=memcheck --leak-check=yes --leak-resolution=high
      --num-callers=100 --show-reachable=yes gdcmTests TestWriteSimple
      $(GDCMDATA_HOME)/012345.002.050.dcm foo.dcm

ChangeLog
Testing/CMakeLists.txt
Testing/TestWriteSimple.cxx [new file with mode: 0644]
src/gdcmBinEntry.cxx
src/gdcmDocument.cxx
src/gdcmDocument.h
src/gdcmElementSet.cxx
src/gdcmElementSet.h
src/gdcmSQItem.cxx

index 019603537c55bcb4128b0c3686252f0e2b3ac970..adc27f6f3a4d5e8c5c1ed9ddaca451c907a58773 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2004-06-18 Eric Boix <Eric.Boix@creatis.insa-lyon.fr>
+    * In order to fix writing of dicom files:
+     - Test/TestWriteSimple.cxx: a simpler example of writing.
+     - Test/CMakeLists.txt changed accordingly.
+     - src/gdcmDocument.cxx:
+       -- The destructor now recursilvely removes potential sequences.
+       -- Bug fix in ::IsJPEG2000()
+       -- ::ReplaceOrCreateByNumber(std::string, guint16, guint16)
+          now handles promotion of gdcmDocEntry to gdcmValEntry in a cleaner
+          manner.
+       -- ::GetValEntryByNumber(guint16, guint16) now defined (as opposed
+          to only declared) and build on top of
+          ::GetDocEntryByNumber(guint16, guint16).
+       -- ::SetEntryByNumber() now uses GetValEntryByNumber(group, element)
+     - src/gdcmElementSet.[h|cxx]: added ::RemoveEntry(gdcmDocEntry *)
+       for usage in destructor and treatement of promotion in
+       ::ReplaceOrCreateByNumber().
+     - src/gdcmSQItem.cxx: destructor should better handle his job.
+      Test/TestWriteSimple now runs (or at least it DOES something).
+    * We can now start hutting memory links. A good starting point is:
+      valgrind -q --skin=memcheck --leak-check=yes --leak-resolution=high
+      --num-callers=100 --show-reachable=yes gdcmTests TestWriteSimple
+      $(GDCMDATA_HOME)/012345.002.050.dcm foo.dcm
+
 2004-06-18 Eric Boix <Eric.Boix@creatis.insa-lyon.fr>
     * Valgrind note: after Mathieu Malaterre teached me how to read
       the valgrind FAQ ;-] (see http://valgrind.kde.org/faq.html), I
index f6dba28301b968d46e704d059dfbd6d04c664284..0540b7ee859569c049abfc88f1e7c5f2e632f1db 100644 (file)
@@ -12,6 +12,7 @@ SET(TEST_SOURCES
   TestDcm2Acr.cxx
   TestHash.cxx
   TestWrite.cxx
+  TestWriteSimple.cxx
 )
 
 # add tests that require data
diff --git a/Testing/TestWriteSimple.cxx b/Testing/TestWriteSimple.cxx
new file mode 100644 (file)
index 0000000..3329491
--- /dev/null
@@ -0,0 +1,39 @@
+#include "gdcmHeader.h"
+#include "gdcmFile.h"
+#include "gdcmDebug.h"
+
+
+int TestWriteSimple(int argc, char* argv[])
+{
+
+  if (argc < 3) 
+    {
+    std::cerr << "Usage :" << std::endl << argv[0] << 
+      " InputHeader OutputDicom" << std::endl;
+    return 0;  
+    }
+
+  const char *header = argv[1];
+  const char *output = argv[2];
+
+  dbg.SetDebug(4);
+  gdcmHeader *f1 = new gdcmHeader( header );
+  gdcmFile   *f2 = new gdcmFile( f1 );
+       
+  f2->GetImageData(); //EXTREMELY IMPORTANT
+  //Otherwise ReadPixel == -1 -> the dicom writing fails completely
+  
+  int dataSize    = f2->GetImageDataSize();
+  // unsigned char cast is necessary to be able to delete the buffer
+  // since deleting a void* is not allowed in c++
+  char *imageData = (char*)f2->GetImageData();
+
+  f2->SetImageData( imageData, dataSize);
+
+  f2->WriteDcmExplVR( output );
+  
+  delete[] imageData;
+
+  return 0;
+}
+
index 4498e27fa085d2360ef094f2216db385de5c758a..c9b156214cf730a86fb96421f75c6d133c54db96 100644 (file)
@@ -1,7 +1,23 @@
-// gdcmBinEntry.cxx
-//-----------------------------------------------------------------------------
-//
+/*=========================================================================
+                                                                                
+  Program:   gdcm
+  Module:    $RCSfile: gdcmBinEntry.cxx,v $
+  Language:  C++
+  Date:      $Date: 2004/06/18 12:26:54 $
+  Version:   $Revision: 1.9 $
+                                                                                
+  Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
+  l'Image). All rights reserved. See Doc/License.txt or
+  http://www.creatis.insa-lyon.fr/Public/Gdcm/License.htm for details.
+                                                                                
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+                                                                                
+=========================================================================*/
+
 #include "gdcmBinEntry.h"
+#include "gdcmDebug.h"
 
 
 //-----------------------------------------------------------------------------
@@ -46,7 +62,9 @@ gdcmBinEntry::~gdcmBinEntry(){
  
 void gdcmBinEntry::Print(std::ostream &os) {
    PrintCommonPart(os);
-   std::cout << " gdcmBinEntry : Print, so WHAT ?" <<std::endl;
+   /// \todo Write a true specialisation of Print i.e. display something
+   ///       for BinEntry extension.
+   dbg.Verbose(1, "gdcmBinEntry::Print: so WHAT ?");
 }
 //-----------------------------------------------------------------------------
 // Public
index eb73f948d73ff61b6afce76059e082e9241a3b96..9dd23bbcd964189f379acf978a324b37bf020e95 100644 (file)
@@ -98,8 +98,6 @@ gdcmDocument::gdcmDocument(const char *inFilename,
    dbg.Verbose(0, "gdcmDocument::gdcmDocument: starting parsing of file: ",
                   filename.c_str());
    rewind(fp);
-   //if (!CheckSwap())
-   //   return false; // to go on compiling
    
    fseek(fp,0L,SEEK_END);
    long lgt = ftell(fp);    
@@ -158,12 +156,26 @@ gdcmDocument::gdcmDocument(bool exception_on_error)
 gdcmDocument::~gdcmDocument (void) {
    RefPubDict = NULL;
    RefShaDict = NULL;
+
+   // Recursive clean up of sequences
+   for (TagDocEntryHT::iterator it = tagHT.begin(); it != tagHT.end(); ++it )
+   {
+      gdcmDocEntry * entry = it->second;
+      if ( gdcmSeqEntry* SeqEntry = dynamic_cast<gdcmSeqEntry*>(entry) )
+      {
+         delete SeqEntry;
+         RemoveEntry(SeqEntry);
+      }
+      else
+      {
+         RemoveEntry(entry);
+      }
+   }
+   tagHT.clear();
 }
 
 //-----------------------------------------------------------------------------
 // Print
-/**
 
 /**
   * \brief   Prints The Dict Entries of THE public Dicom Dictionary
@@ -385,8 +397,8 @@ bool gdcmDocument::IsJPEGLossless(void)
  */
 bool gdcmDocument::IsJPEG2000(void)
 {
-   return (   IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_70)
-           || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_90) );
+   return (   IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_90)
+           || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_91) );
 }
 
 /**
@@ -557,21 +569,53 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
                                          std::string Value, 
                                          guint16 Group, 
                                          guint16 Elem ){
-   gdcmDocEntry* a;
-   gdcmValEntry* b;    
-   a = GetDocEntryByNumber( Group, Elem);
-   if (a == NULL) {
-      a =NewDocEntryByNumber(Group, Elem);
-      if (a == NULL) 
-         return NULL;
-               b = new gdcmValEntry(a);
-      AddEntry(b);
-   }   
+   gdcmDocEntry* CurrentEntry;
+   gdcmValEntry* ValEntry;
+
+   CurrentEntry = GetDocEntryByNumber( Group, Elem);
+   if (!CurrentEntry)
+   {
+      // The entry wasn't present and we simply create the required ValEntry:
+      CurrentEntry = NewDocEntryByNumber(Group, Elem);
+      if (!CurrentEntry)
+      {
+         dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: call to"
+                        " NewDocEntryByNumber failed.");
+         return (gdcmValEntry *)0;
+      }
+      ValEntry = new gdcmValEntry(CurrentEntry);
+      if ( !AddEntry(ValEntry))
+      {
+         dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: AddEntry"
+                        " failed allthough this is a creation.");
+      }
+   }
+   else
+   {
+      ValEntry = dynamic_cast< gdcmValEntry* >(CurrentEntry);
+      if ( !ValEntry )
+      {
+         // We need to promote the gdcmDocEntry to a gdcmValEntry:
+         ValEntry = new gdcmValEntry(CurrentEntry);
+         if (!RemoveEntry(CurrentEntry))
+         {
+            dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: removal"
+                           " of previous DocEntry failed.");
+            return (gdcmValEntry *)0;
+         }
+         if ( !AddEntry(ValEntry))
+         {
+            dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: adding"
+                           " promoted ValEntry failed.");
+            return (gdcmValEntry *)0;
+         }
+      }
+   }
+
    SetEntryByNumber(Value, Group, Elem);
-   b->SetValue(Value);
-   return (gdcmValEntry*)b;
-}   
 
+   return ValEntry;
+}   
 
 /*
  * \brief   Modifies the value of a given Header Entry (Dicom Element)
@@ -754,32 +798,29 @@ bool gdcmDocument::SetEntryByNumber(std::string content,
                                   guint16 group,
                                   guint16 element) 
 {
-   TagKey key = gdcmDictEntry::TranslateToKey(group, element);
-   if ( ! tagHT.count(key))
+   gdcmValEntry* ValEntry = GetValEntryByNumber(group, element);
+   if (!ValEntry)
+   {
+      dbg.Verbose(0, "gdcmDocument::SetEntryByNumber: no corresponding",
+                     " ValEntry (try promotion first).");
       return false;
-   int l = content.length();
-   if(l%2) // Non even length are padded with a space (020H).
-   {  
-      l++;
-      content = content + '\0';
    }
+
+   // Non even content must be padded with a space (020H).
+   if((content.length())%2)
+      content = content + '\0';
       
-   gdcmValEntry * a;
-   a = (gdcmValEntry *)tagHT[key];
-           
-   a->SetValue(content);
-   
-   VRKey vr = a->GetVR();
+   ValEntry->SetValue(content);
    
-   guint32 lgr;
+   // Integers have a special treatement for their length:
+   VRKey vr = ValEntry->GetVR();
    if( (vr == "US") || (vr == "SS") ) 
-      lgr = 2;
+      ValEntry->SetLength(2);
    else if( (vr == "UL") || (vr == "SL") )
-      lgr = 4;
+      ValEntry->SetLength(4);
    else
-      lgr = l;   
+      ValEntry->SetLength(content.length());
 
-   a->SetLength(lgr);   
    return true;
 } 
 
@@ -1006,6 +1047,25 @@ gdcmDocEntry* gdcmDocument::GetDocEntryByNumber(guint16 group, guint16 element)
    return tagHT.find(key)->second;
 }
 
+/**
+ * \brief  Same as \ref gdcmDocument::GetDocEntryByNumber except it only
+ *         returns a result when the corresponding entry is of type
+ *         ValEntry.
+ * @return When present, the corresponding ValEntry. 
+ */
+gdcmValEntry* gdcmDocument::GetValEntryByNumber(guint16 group, guint16 element)
+{
+  gdcmDocEntry* CurrentEntry = GetDocEntryByNumber(group, element);
+  if (! CurrentEntry)
+     return (gdcmValEntry*)0;
+  if ( gdcmValEntry* ValEntry = dynamic_cast<gdcmValEntry*>(CurrentEntry) )
+  {
+     return ValEntry;
+  }
+  dbg.Verbose(0, "gdcmDocument::GetValEntryByNumber: unfound ValEntry.");
+  return (gdcmValEntry*)0;
+}
+
 /**
  * \brief         Loads the element while preserving the current
  *                underlying file position indicator as opposed to
@@ -1229,7 +1289,6 @@ bool gdcmDocument::WriteEntries(FILE *_fp,FileType type)
    for (TagDocEntryHT::iterator it = tagHT.begin(); it != tagHT.end(); ++it )
    {
       gdcmDocEntry * entry = it->second;
-      entry->Print();
 
       if ( type == gdcmACR ){ 
          if (entry->GetGroup() < 0x0008)
index ee7b20a403ca49a7a127e11b67028cc12ff59413..bc12f0d55906bb9a7a1b4ed2f70218ef134b1440 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.h,v $
   Language:  C++
-  Date:      $Date: 2004/06/18 00:11:45 $
-  Version:   $Revision: 1.10 $
+  Date:      $Date: 2004/06/18 12:26:54 $
+  Version:   $Revision: 1.11 $
  
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
@@ -16,8 +16,6 @@
  
 =========================================================================*/
 
-// gdcmDocument.h
-//-----------------------------------------------------------------------------
 #ifndef GDCMDOCUMENT_H
 #define GDCMDOCUMENT_H
 
index 36ebbd2b32ef09b888e0bad868309ba3740710d7..e98a34462b713a6ef8a5b2e4bc71662397b22eb9 100644 (file)
@@ -70,7 +70,8 @@ bool gdcmElementSet::AddEntry( gdcmDocEntry *NewEntry) {
 
    if(tagHT.count(key) == 1)
    {
-      dbg.Verbose(1, "gdcmElementSet::AddEntry key already present: ", key.c_str());
+      dbg.Verbose(1, "gdcmElementSet::AddEntry key already present: ",
+                  key.c_str());
       return(false);
    } 
    else 
@@ -80,3 +81,20 @@ bool gdcmElementSet::AddEntry( gdcmDocEntry *NewEntry) {
    }   
 }
 
+/**
+ * \brief   Clear the hash table from given entry.
+ * @param   EntryToRemove Entry to remove.
+ */
+bool gdcmElementSet::RemoveEntry( gdcmDocEntry *EntryToRemove)
+{
+   TagKey key = EntryToRemove->GetKey();
+   if(tagHT.count(key) == 1)
+   {
+      tagHT.erase(key);
+      dbg.Verbose(1, "gdcmElementSet::RemoveEntry: one element erased.");
+      return true;
+   }
+
+   dbg.Verbose(0, "gdcmElementSet::RemoveEntry: key not present: ");
+   return(false);
+}
index a410629e8a11ffa0d98638b19ef6323249492250..826b85cf32d27375d488bc41aacf9ec81fb2e292 100644 (file)
@@ -17,14 +17,13 @@ class GDCM_EXPORT gdcmElementSet : public gdcmDocEntrySet
 public:
    gdcmElementSet(int);
    ~gdcmElementSet(void);
-   virtual bool AddEntry(gdcmDocEntry *Entry); // add to the H Table
+   virtual bool AddEntry(gdcmDocEntry *Entry);
+   virtual bool RemoveEntry(gdcmDocEntry *EntryToRemove);
 
-   virtual void Print        (std::ostream &os = std::cout); 
+   virtual void Print(std::ostream &os = std::cout); 
     
 protected:
-
 // Variables
-
    /// Hash Table (map), to provide fast access
    TagDocEntryHT tagHT; 
      
index a3d5161682df04950bd55cd0a0f6dc6316d4b232..2dd621767491e3733600bcf9f6225a5a579dfa04 100644 (file)
@@ -2,6 +2,7 @@
 //-----------------------------------------------------------------------------
 //
 #include "gdcmSQItem.h"
+#include "gdcmSeqEntry.h"
 #include "gdcmGlobal.h"
 #include "gdcmUtil.h"
 #include "gdcmValEntry.h"
@@ -27,8 +28,17 @@ gdcmSQItem::~gdcmSQItem()
        cc != docEntries.end();
        ++cc)
    {
-      delete *cc;
+      gdcmDocEntry* DocEntry = *cc;
+      if ( gdcmSeqEntry* SeqEntry = dynamic_cast<gdcmSeqEntry*>(DocEntry) )
+      {
+         delete SeqEntry;
+      }
+      else
+      {
+         delete DocEntry;
+      }
    }
+   docEntries.clear();
 }