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

📄 gdcmfile.cxx

📁 DTMK软件开发包,此为开源软件,是一款很好的医学图像开发资源.
💻 CXX
📖 第 1 页 / 共 5 页
字号:
bool File::AnonymizeFile()
{
   // If Anonymisation list is empty, let's perform some basic anonymization
   if ( UserAnonymizeList.begin() == UserAnonymizeList.end() )
   {
      // If exist, replace by spaces
      SetValEntry ("  ",0x0010, 0x2154); // Telephone   
      SetValEntry ("  ",0x0010, 0x1040); // Adress
      SetValEntry ("  ",0x0010, 0x0020); // Patient ID

      DocEntry* patientNameHE = GetDocEntry (0x0010, 0x0010);
  
      if ( patientNameHE ) // we replace it by Study Instance UID (why not ?)
      {
         std::string studyInstanceUID =  GetEntryValue (0x0020, 0x000d);
         if ( studyInstanceUID != GDCM_UNFOUND )
         {
            SetValEntry(studyInstanceUID, 0x0010, 0x0010);
         }
         else
         {
            SetValEntry("anonymized", 0x0010, 0x0010);
         }
      }
   }
   else
   {
      gdcm::DocEntry *d;
      for (ListElements::iterator it = UserAnonymizeList.begin();  
                                  it != UserAnonymizeList.end();
                                ++it)
      {  
         d = GetDocEntry( (*it).Group, (*it).Elem);

         if ( d == NULL)
            continue;

         if ( dynamic_cast<SeqEntry *>(d) )
         {
            gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry ");
            continue;
         }

         if ( dynamic_cast<BinEntry *>(d) )
         {
            gdcmWarningMacro( "To 'Anonymize' a BinEntry, better use AnonymizeNoLoad (FIXME) ");
            continue;
         }
         else
            SetValEntry ((*it).Value, (*it).Group, (*it).Elem);
      }
}

  // In order to make definitively impossible any further identification
  // remove or replace all the stuff that contains a Date

//0008 0012 DA ID Instance Creation Date
//0008 0020 DA ID Study Date
//0008 0021 DA ID Series Date
//0008 0022 DA ID Acquisition Date
//0008 0023 DA ID Content Date
//0008 0024 DA ID Overlay Date
//0008 0025 DA ID Curve Date
//0008 002a DT ID Acquisition Datetime
//0018 9074 DT ACQ Frame Acquisition Datetime
//0018 9151 DT ACQ Frame Reference Datetime
//0018 a002 DT ACQ Contribution Date Time
//0020 3403 SH REL Modified Image Date (RET)
//0032 0032 DA SDY Study Verified Date
//0032 0034 DA SDY Study Read Date
//0032 1000 DA SDY Scheduled Study Start Date
//0032 1010 DA SDY Scheduled Study Stop Date
//0032 1040 DA SDY Study Arrival Date
//0032 1050 DA SDY Study Completion Date
//0038 001a DA VIS Scheduled Admission Date
//0038 001c DA VIS Scheduled Discharge Date
//0038 0020 DA VIS Admitting Date
//0038 0030 DA VIS Discharge Date
//0040 0002 DA PRC Scheduled Procedure Step Start Date
//0040 0004 DA PRC Scheduled Procedure Step End Date
//0040 0244 DA PRC Performed Procedure Step Start Date
//0040 0250 DA PRC Performed Procedure Step End Date
//0040 2004 DA PRC Issue Date of Imaging Service Request
//0040 4005 DT PRC Scheduled Procedure Step Start Date and Time
//0040 4011 DT PRC Expected Completion Date and Time
//0040 a030 DT PRC Verification Date Time
//0040 a032 DT PRC Observation Date Time
//0040 a120 DT PRC DateTime
//0040 a121 DA PRC Date
//0040 a13a DT PRC Referenced Datetime
//0070 0082 DA ??? Presentation Creation Date
//0100 0420 DT ??? SOP Autorization Date and Time
//0400 0105 DT ??? Digital Signature DateTime
//2100 0040 DA PJ Creation Date
//3006 0008 DA SSET Structure Set Date
//3008 0024 DA ??? Treatment Control Point Date
//3008 0054 DA ??? First Treatment Date
//3008 0056 DA ??? Most Recent Treatment Date
//3008 0162 DA ??? Safe Position Exit Date
//3008 0166 DA ??? Safe Position Return Date
//3008 0250 DA ??? Treatment Date
//300a 0006 DA RT RT Plan Date
//300a 022c DA RT Air Kerma Rate Reference Date
//300e 0004 DA RT Review Date

   return true;
}

/**
 * \brief Performs some consistency checking on various 'File related' 
 *       (as opposed to 'DicomDir related') entries 
 *       then writes in a file all the (Dicom Elements) included the Pixels 
 * @param fileName file name to write to
 * @param writetype type of the file to be written 
 *          (ACR, ExplicitVR, ImplicitVR)
 */
bool File::Write(std::string fileName, FileType writetype)
{
   std::ofstream *fp = new std::ofstream(fileName.c_str(), 
                                         std::ios::out | std::ios::binary);
   if (*fp == NULL)
   {
      gdcmWarningMacro("Failed to open (write) File: " << fileName.c_str());
      return false;
   }

   // Entry : 0002|0000 = group length -> recalculated
   ValEntry *e0000 = GetValEntry(0x0002,0x0000);
   if ( e0000 )
   {
      itksys_ios::ostringstream sLen;
      sLen << ComputeGroup0002Length( );
      e0000->SetValue(sLen.str());
   }

   int i_lgPix = GetEntryLength(GrPixel, NumPixel);
   if (i_lgPix != -2)
   {
      // no (GrPixel, NumPixel) element
      std::string s_lgPix = Util::Format("%d", i_lgPix+12);
      s_lgPix = Util::DicomString( s_lgPix.c_str() );
      InsertValEntry(s_lgPix,GrPixel, 0x0000);
   }
   Document::WriteContent(fp, writetype);

   fp->close();
   delete fp;

   return true;
}

//-----------------------------------------------------------------------------
// Protected


//-----------------------------------------------------------------------------
// Private
/**
 * \brief Parse pixel data from disk of [multi-]fragment RLE encoding.
 *        Compute the RLE extra information and store it in \ref RLEInfo
 *        for later pixel retrieval usage.
 */
void File::ComputeRLEInfo()
{
   std::string ts = GetTransferSyntax();
   if ( !Global::GetTS()->IsRLELossless(ts) ) 
   {
      return;
   }

   // Encoded pixel data: for the time being we are only concerned with
   // Jpeg or RLE Pixel data encodings.
   // As stated in PS 3.5-2003, section 8.2 p44:
   // "If sent in Encapsulated Format (i.e. other than the Native Format) the
   //  value representation OB is used".
   // Hence we expect an OB value representation. Concerning OB VR,
   // the section PS 3.5-2003, section A.4.c p 58-59, states:
   // "For the Value Representations OB and OW, the encoding shall meet the
   //   following specifications depending on the Data element tag:"
   //   [...snip...]
   //    - the first item in the sequence of items before the encoded pixel
   //      data stream shall be basic offset table item. The basic offset table
   //      item value, however, is not required to be present"
   ReadEncapsulatedBasicOffsetTable();

   // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G)
   // Loop on the individual frame[s] and store the information
   // on the RLE fragments in a RLEFramesInfo.
   // Note: - when only a single frame is present, this is a
   //         classical image.
   //       - when more than one frame are present, then we are in 
   //         the case of a multi-frame image.
   long frameLength;
   int i=0;
   uint32_t sum = 0;
   while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) != 0 )
   { 
      // Since we have read the basic offset table, let's check the value were correct
      // or else produce a warning:
      if ( BasicOffsetTableItemValue )
        {
        // If a BasicOffsetTableItemValue was read
        uint32_t individualLength = BasicOffsetTableItemValue[i];
        assert( individualLength == sum ); // REMOVE that if this is a problem
        if( individualLength != sum )
          {
          gdcmWarningMacro( "BasicOffsetTableItemValue differs from the fragment lenght" );
          }
        sum += frameLength + 8;
        i++;
        }
      // Parse the RLE Header and store the corresponding RLE Segment
      // Offset Table information on fragments of this current Frame.
      // Note that the fragment pixels themselves are not loaded
      // (but just skipped).
      long frameOffset = Fp->tellg(); // once per fragment

      uint32_t nbRleSegments = ReadInt32();
      if ( nbRleSegments > 16 )
      {
         // There should be at most 15 segments (refer to RLEFrame class)
         gdcmWarningMacro( "Too many segments.");
      }
 
      uint32_t rleSegmentOffsetTable[16];
      for( int k = 1; k <= 15; k++ )
      {
         rleSegmentOffsetTable[k] = ReadInt32();
      }

      // Deduce from both RLE Header and frameLength 
      // the fragment length, and again store this info
      // in a RLEFramesInfo.
      long rleSegmentLength[15];
      // skipping (not reading) RLE Segments
      if ( nbRleSegments > 1)
      {
         for(unsigned int k = 1; k <= nbRleSegments-1; k++)
         {
             rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
                                  - rleSegmentOffsetTable[k];
             SkipBytes(rleSegmentLength[k]);
          }
       }

       rleSegmentLength[nbRleSegments] = frameLength 
                                      - rleSegmentOffsetTable[nbRleSegments];
       SkipBytes(rleSegmentLength[nbRleSegments]);

       // Store the collected info
       RLEFrame *newFrame = new RLEFrame;
       newFrame->SetNumberOfFragments(nbRleSegments);
       for( unsigned int uk = 1; uk <= nbRleSegments; uk++ )
       {
          newFrame->SetOffset(uk,frameOffset + rleSegmentOffsetTable[uk]);
          newFrame->SetLength(uk,rleSegmentLength[uk]);
       }
       RLEInfo->AddFrame(newFrame);
   }

   // Make sure that  we encounter a 'Sequence Delimiter Item'
   // at the end of the item :
   if ( !ReadTag(0xfffe, 0xe0dd) ) // once per RLE File
   {
      gdcmWarningMacro( "No sequence delimiter item at end of RLE item sequence");
   }
}

/**
 * \brief Parse pixel data from disk of [multi-]fragment Jpeg encoding.
 *        Compute the jpeg extra information (fragment[s] offset[s] and
 *        length) and store it[them] in \ref JPEGInfo for later pixel
 *        retrieval usage.
 */
void File::ComputeJPEGFragmentInfo()
{
   // If you need to, look for comments of ComputeRLEInfo().
   std::string ts = GetTransferSyntax();
   if ( ! Global::GetTS()->IsJPEG(ts) )
   {
      return;
   }

   ReadEncapsulatedBasicOffsetTable();

   // Loop on the fragments[s] and store the parsed information in a
   // JPEGInfo.
   long fragmentLength;
   int i=0;
   uint32_t sum = 0;
   while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) != 0 )
   { 
      // Since we have read the basic offset table, let's check the value were correct
      // or else produce a warning:
      // A.4 Transfer syntaxes for encapsulation of encoded pixel data:
      // When the Item Value is present, the Basic Offset Table Item Value shall contain
      // concatenated 32-bit unsigned integer values that are byte offsets to the first
      // byte of the Item Tag of the first fragment for each frame in the Sequence of
      // Items. These offsets are measured from the first byte of the first Item Tag
      // following the Basic Offset Table item (See Table A.4-2).

      if ( BasicOffsetTableItemValue )
        {
        // If a BasicOffsetTableItemValue was read
        uint32_t individualLength = BasicOffsetTableItemValue[i];
        //assert( individualLength == sum ); // Seems like 00191113.dcm is off by one ??
        if( individualLength != sum )
          {
          gdcmWarningMacro( "BasicOffsetTableItemValue differs from the fragment lenght:" <<
              individualLength << " != " << sum );
          }
        sum += fragmentLength + 8;
        i++;
        }

      long fragmentOffset = Fp->tellg(); // Once per fragment
      // Store the collected info
      JPEGFragment *newFragment = new JPEGFragment;
      newFragment->SetOffset(fragmentOffset);
      newFragment->SetLength(fragmentLength);
      JPEGInfo->AddFragment(newFragment);

      SkipBytes(fragmentLength);
   }

   // Make sure that  we encounter a 'Sequence Delimiter Item'
   // at the end of the item :
   if ( !ReadTag(0xfffe, 0xe0dd) )
   {
      gdcmWarningMacro( "No sequence delimiter item at end of JPEG item sequence");
   }
}

/**
 * \brief   Assuming the internal file pointer \ref Document::Fp 
 *          is placed at the beginning of a tag, check whether this
 *          tag is (TestGroup, TestElem).
 * \warning On success the internal file pointer \ref Document::Fp
 *          is modified to point after the tag.
 *          On failure (i.e. when the tag wasn't the expected tag
 *          (TestGroup, TestElem) the internal file pointer
 *          \ref Document::Fp is restored to it's original position.
 * @param   testGroup The expected group   of the tag.
 * @param   testElem  The expected Element of the tag.
 * @return  True on success, false otherwise.
 */
bool File::ReadTag(uint16_t testGroup, uint16_t testElem)
{
   long positionOnEntry = Fp->tellg(); // Only when reading fragments
   //long currentPosition = positionOnEntry;      // On debugging purposes

   // Read the Item Tag group and element, and make
   // sure they are what we expected:
   uint16_t itemTagGroup;
   uint16_t itemTagElem;
   try
   {
      itemTagGroup = ReadInt16();
      itemTagElem  = ReadInt16();
   }
   catch ( FormatError )
   {
      gdcmErrorMacro( "Can not read tag for "
       << "   We should have found tag ("
       << DictEntry::TranslateToKey(testGroup,testElem) << ")"
       ) ;

      return false;
   }
   if ( itemTagGroup != testGroup || itemTagElem != testElem )
   {
       // in order not to pollute output we don't warn on 'delimitors'
      if (itemTagGroup != 0xfffe ||  testGroup != 0xfffe )
      gdcmWarningMacro( "Wrong Item Tag found:"
       << "   We should have found tag ("
       << std::hex << testGroup << "," << testElem << ")" << std::endl
       << "   but instead we encountered tag ("
       << std::hex << itemTagGroup << "," << itemTagElem << ")"
       << "  at address: " << "  0x(" << (unsigned int)positionOnEntry << ")" 
       ) ;
      Fp->seekg(positionOnEntry, std::ios::beg);

      return false;
   }
   return true;
}

/**
 * \brief   Assuming the internal file pointer \ref Document::Fp 
 *          is placed at the beginning of a tag (TestGroup, TestElement),
 *          read the length associated to the Tag.
 * \warning On success the internal file pointer \ref Document::Fp
 *          is modified to point after the tag and it's length.
 *          On failure (i.e

⌨️ 快捷键说明

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