⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gdcmdocument.cxx

📁 DTMK软件开发包,此为开源软件,是一款很好的医学图像开发资源.
💻 CXX
📖 第 1 页 / 共 5 页
字号:
   return IsParsable();
}


/**
 * \brief   Predicate for dicom version 3 file.
 * @return  True when the file is a dicom version 3.
 */
bool Document::IsDicomV3()
{
   // Checking if Transfer Syntax exists is enough
   // Anyway, it's too late check if the 'Preamble' was found ...
   // And ... would it be a rich idea to check ?
   // (some 'no Preamble' DICOM images exist !)
   return GetDocEntry(0x0002, 0x0010) != NULL;
}

/**
 * \brief   Predicate for Papyrus file
 *          Dedicated to whomsoever it may concern
 * @return  True when the file is a Papyrus file.
 */
bool Document::IsPapyrus()
{
   // check for Papyrus private Sequence
   DocEntry *e = GetDocEntry(0x0041, 0x1050);
   if ( !e )
      return false;
   // check if it's actually a Sequence
   if ( !dynamic_cast<SeqEntry*>(e) )
      return  false;
   return true;
}

/**
 * \brief  returns the File Type 
 *         (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown)
 * @return the FileType code
 */
FileType Document::GetFileType()
{
   return Filetype;
}

/**
 * \brief   Accessor to the Transfer Syntax (when present) of the
 *          current document (it internally handles reading the
 *          value from disk when only parsing occured).
 * @return  The encountered Transfer Syntax of the current document, if DICOM.
 *          GDCM_UNKNOWN for ACR-NEMA files (or broken headers ...)
 */
std::string Document::GetTransferSyntax()
{
   DocEntry *entry = GetDocEntry(0x0002, 0x0010);
   if ( !entry )
   {
      return GDCM_UNKNOWN;
   }

   // The entry might be present but not loaded (parsing and loading
   // happen at different stages): try loading and proceed with check...
   LoadDocEntrySafe(entry);
   if (ValEntry *valEntry = dynamic_cast< ValEntry* >(entry) )
   {
      std::string transfer = valEntry->GetValue();
      // The actual transfer (as read from disk) might be padded. We
      // first need to remove the potential padding. We can make the
      // weak assumption that padding was not executed with digits...
      if  ( transfer.length() == 0 )
      {
         // for brain damaged headers
         return GDCM_UNKNOWN;
      }
      while ( !isdigit((unsigned char)transfer[transfer.length()-1]) )
      {
         transfer.erase(transfer.length()-1, 1);
         if  ( transfer.length() == 0 )
         {
            // for brain damaged headers
            gdcmWarningMacro( "Transfer Syntax contains no valid character.");
            return GDCM_UNKNOWN;
         }
      }
      return transfer;
   }
   return GDCM_UNKNOWN;
}

/**
 * \brief Accesses the info from 0002,0010 : Transfer Syntax and TS
 * @return The full Transfer Syntax Name (as opposed to Transfer Syntax UID)
 */
std::string Document::GetTransferSyntaxName()
{
   // use the TS (TS : Transfer Syntax)
   std::string transferSyntax = GetEntryValue(0x0002,0x0010);

   if ( (transferSyntax.find(GDCM_NOTLOADED) < transferSyntax.length()) )
   {
      gdcmErrorMacro( "Transfer Syntax not loaded. " << std::endl
               << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE" );
      return "Uncompressed ACR-NEMA";
   }
   if ( transferSyntax == GDCM_UNFOUND )
   {
      gdcmDebugMacro( "Unfound Transfer Syntax (0002,0010)");
      return "Uncompressed ACR-NEMA";
   }

   // we do it only when we need it
   const TSKey &tsName = Global::GetTS()->GetValue( transferSyntax );

   // Global::GetTS() is a global static you shall never try to delete it!
   return tsName;
}
//
// --------------- Swap Code ------------------
/**
 * \brief   Swaps the bytes so they agree with the processor order
 * @return  The properly swaped 16 bits integer.
 */
uint16_t Document::SwapShort(uint16_t a)
{
   if ( SwapCode == 4321 || SwapCode == 2143 )
   {
      //a = ((( a << 8 ) & 0xff00 ) | (( a >> 8 ) & 0x00ff ) );
      // Save CPU time
      a = ( a << 8 ) | ( a >> 8 );
   }
   return a;
}

/**
 * \brief   Swaps back the bytes of 4-byte long integer accordingly to
 *          processor order.
 * @return  The properly swaped 32 bits integer.
 */
uint32_t Document::SwapLong(uint32_t a)
{
   switch (SwapCode)
   {
      case 1234 :
         break;
      case 4321 :
//         a=( ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000) |
//             ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
// save CPU time
         a=( ( a<<24)               | ((a<<8)  & 0x00ff0000) |
             ((a>>8)  & 0x0000ff00) |  (a>>24)                );
         break;
      case 3412 :
//       a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
         a=( (a<<16)                | (a>>16)  );
         break;
      case 2143 :
         a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
      break;
      default :
         gdcmErrorMacro( "Unexpected swap code:" << SwapCode );
         a = 0;
   }
   return a;
}

//
// -----------------File I/O ---------------
/**
 * \brief  Tries to open the file \ref Document::Filename and
 *         checks the preamble when existing.
 * @return The FILE pointer on success.
 */
std::ifstream *Document::OpenFile()
{
   HasDCMPreamble = false;
   if (Filename.length() == 0)
   {
      return 0;
   }

   if ( Fp )
   {
      gdcmDebugMacro( "File already open: " << Filename.c_str());
      CloseFile();
   }

   Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary);
   if ( ! *Fp )
   {
   // Don't user gdcmErrorMacro :
   // a spurious message will appear when you use, for instance
   // gdcm::FileHelper *fh = new gdcm::FileHelper( outputFileName );
   // to create outputFileName.

   // FIXME : if the upper comment is still useful
   //         --> the constructor is not so good ...

      gdcmWarningMacro( "Cannot open file: " << Filename.c_str());
      delete Fp;
      Fp = 0;
      return 0;
      //exit(1); // No function is allowed to leave the application instead
                 // of warning the caller
   }
   if( !CanReadFile(*Fp, HasDCMPreamble) )
   {
      // -- Neither ACR/No Preamble Dicom nor DICOMV3 file
      CloseFile();
      gdcmWarningMacro( "Neither ACR/No Preamble Dicom nor DICOMV3 file: "
                      << Filename.c_str());
      return 0;
   }
   return Fp;
}

bool Document::CanReadFile(std::istream &os, bool &hasPreamble)
{
   hasPreamble = false;
   uint16_t zero = 0;
   os.read((char*)&zero, (size_t)2);
   if ( os.eof() )
   {
      return false;
   }

   //-- Broken ACR or DICOM with no Preamble; may start with a Shadow Group --
   // FIXME : We cannot be sure the preable is only zeroes..
   //         (see ACUSON-24-YBR_FULL-RLE.dcm )
   if (
       zero == 0x0001 || zero == 0x0100 || zero == 0x0002 || zero == 0x0200 ||
       zero == 0x0003 || zero == 0x0300 || zero == 0x0004 || zero == 0x0400 ||
       zero == 0x0005 || zero == 0x0500 || zero == 0x0006 || zero == 0x0600 ||
       zero == 0x0007 || zero == 0x0700 || zero == 0x0008 || zero == 0x0800 )
   {
      std::string msg = Util::Format(
        "ACR/DICOM starting by 0x(%04x) at the beginning of the file\n", zero);
      // FIXME : is it a Warning message, or a Debug message?
      gdcmWarningMacro( msg.c_str() );
      return true;
   }

   //-- DICOM --
   os.seekg(126L, std::ios::cur);  // Once per Document
   char dicm[4]; // = {' ',' ',' ',' '};
   os.read(dicm,  (size_t)4);
   if ( os.eof() )
   {
      return false;
   }
   if ( memcmp(dicm, "DICM", 4) == 0 )
   {
      hasPreamble = true;
      return true;
   }
   return false;
}

/**
 * \brief closes the file
 * @return  TRUE if the close was successfull
 */
bool Document::CloseFile()
{
   if ( Fp )
   {
      Fp->close();
      delete Fp;
      Fp = 0;
   }
   return true;
}

/**
 * \brief Writes in a file all the Entries (Dicom Elements)
 * @param fp file pointer on an already open file (actually: Output File Stream)
 * @param filetype Type of the File to be written
 *          (ACR-NEMA, ExplicitVR, ImplicitVR)
 */
void Document::WriteContent(std::ofstream *fp, FileType filetype)
{
   // Skip if user wants to write an ACR-NEMA file

   if ( filetype == ImplicitVR || filetype == ExplicitVR ||
        filetype == JPEG || filetype == JPEG2000 )
   {
      // writing Dicom File Preamble
      char filePreamble[128];
      memset(filePreamble, 0, 128);
      fp->write(filePreamble, 128);
      fp->write("DICM", 4);
   }

   /*
    * \todo rewrite later, if really usefull
    *       - 'Group Length' element is optional in DICOM
    *       - but un-updated odd groups lengthes can causes pb
    *         (xmedcon breaker)
    *
    * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) )
    *    UpdateGroupLength(false,filetype);
    * if ( filetype == ACR)
    *    UpdateGroupLength(true,ACR);
    *
    * --> Computing group length for groups with embeded Sequences
    * --> was too much tricky / we were [in a hurry / too lazy]
    * --> We don't write the element 0x0000 (group length)
    */

   ElementSet::WriteContent(fp, filetype); // This one is recursive
}

// -----------------------------------------
// Content entries 
/**
 * \brief Loads (from disk) the element content 
 *        when a string is not suitable
 * @param group   group number of the Entry 
 * @param elem  element number of the Entry
 */
void Document::LoadEntryBinArea(uint16_t group, uint16_t elem)
{
   // Search the corresponding DocEntry
   DocEntry *docElement = GetDocEntry(group, elem);
   if ( !docElement )
   {
      gdcmDebugMacro(std::hex << group << "|" << elem 
                       <<  " doesn't exist" );
      return;
   }
   BinEntry *binElement = dynamic_cast<BinEntry *>(docElement);
   if ( !binElement )
   {
      gdcmWarningMacro(std::hex << group << "|" << elem 
                       <<  "is NOT a BinEntry");
      return;
   }
   LoadEntryBinArea(binElement);
}

/**
 * \brief Loads (from disk) the element content 
 *        when a string is not suitable
 * @param elem  Entry whose binArea is going to be loaded
 */
void Document::LoadEntryBinArea(BinEntry *elem) 
{
   if (elem->GetBinArea() )
      return;

   bool openFile = !Fp;
   if ( openFile )
      OpenFile();

   size_t o =(size_t)elem->GetOffset();
   Fp->seekg(o, std::ios::beg);

   size_t l = elem->GetLength();
   uint8_t *a = new uint8_t[l];
   if ( !a )
   {
      gdcmWarningMacro(  "Cannot allocate BinEntry content for : "
                       << std::hex << elem->GetGroup() 
                       << "|" << elem->GetElement() );
      return;
   }

   // Read the data
   Fp->read((char*)a, l);
   if ( Fp->fail() || Fp->eof() )
   {
      delete[] a;
      return;
   }

   elem->SetBinArea(a);

   if ( openFile )
      CloseFile();
}

/**
 * \brief  Loads the element while preserving the current
 *         underlying file position indicator as opposed to
 *        LoadDocEntry that modifies it.
 * @param entry   DocEntry whose value will be loaded. 
 */
void Document::LoadDocEntrySafe(DocEntry *entry)
{
   if ( Fp )
   {
      long PositionOnEntry = Fp->tellg();
      LoadDocEntry(entry);
      Fp->seekg(PositionOnEntry, std::ios::beg);
   }
}

/**
 * \brief   Compares two documents, according to \ref DicomDir rules
 * \warning Does NOT work with ACR-NEMA files
 * \todo    Find a trick to solve the pb (use RET fields ?)
 * @param   document to compare with current one
 * @return  true if 'smaller'
 */
bool Document::operator<(Document &document)
{
   // Patient Name
   std::string s1 = GetEntryValue(0x0010,0x0010);
   std::string s2 = document.GetEntryValue(0x0010,0x0010);
   if (s1 < s2)
   {
      return true;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -