+ 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("anonymised", 0x0010, 0x0010);
+ }
+ }
+ }
+ else
+ {
+ gdcm::DocEntry *d;
+ for (ListElements::iterator it = AnonymizeList.begin();
+ it != AnonymizeList.end();
+ ++it)
+ {
+ d = GetDocEntry( (*it).Group, (*it).Elem);
+
+ if ( d == NULL)
+ continue;
+
+ if ( dynamic_cast<BinEntry *>(d)
+ || dynamic_cast<SeqEntry *>(d) )
+ continue;
+
+ 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 filetype Type of the File to be written
+ * (ACR, ExplicitVR, ImplicitVR)
+ */
+bool File::Write(std::string fileName, FileType filetype)
+{
+ 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 *e0002 = GetValEntry(0x0002,0x0000);
+ if( e0002 )
+ {
+ std::ostringstream sLen;
+ sLen << ComputeGroup0002Length(filetype);
+ e0002->SetValue(sLen.str());
+ }
+
+ // Bits Allocated
+ if ( GetEntryValue(0x0028,0x0100) == "12")
+ {
+ SetValEntry("16", 0x0028,0x0100);
+ }
+
+ 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);
+ }
+
+ // FIXME : should be nice if we could move it to File
+ // (or in future gdcmPixelData class)
+
+ // Drop Palette Color, if necessary
+ if ( GetEntryValue(0x0028,0x0002).c_str()[0] == '3' )
+ {
+ // if SamplesPerPixel = 3, sure we don't need any LUT !
+ // Drop 0028|1101, 0028|1102, 0028|1103
+ // Drop 0028|1201, 0028|1202, 0028|1203
+
+ DocEntry *e = GetDocEntry(0x0028,0x01101);
+ if (e)
+ {
+ RemoveEntryNoDestroy(e);
+ }
+ e = GetDocEntry(0x0028,0x1102);
+ if (e)
+ {
+ RemoveEntryNoDestroy(e);
+ }
+ e = GetDocEntry(0x0028,0x1103);
+ if (e)
+ {
+ RemoveEntryNoDestroy(e);
+ }
+ e = GetDocEntry(0x0028,0x01201);
+ if (e)
+ {
+ RemoveEntryNoDestroy(e);
+ }
+ e = GetDocEntry(0x0028,0x1202);
+ if (e)
+ {
+ RemoveEntryNoDestroy(e);
+ }
+ e = GetDocEntry(0x0028,0x1203);
+ if (e)
+ {
+ RemoveEntryNoDestroy(e);
+ }
+ }
+
+ Document::WriteContent(fp, filetype);
+
+ fp->close();
+ delete fp;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Protected
+/**
+ * \brief Initialize a default DICOM File that should contain all the
+ * field require by other reader. DICOM standard does not
+ * explicitely defines those fields, heuristic has been choosen.
+ * This is not perfect as we are writting a CT image...
+ */
+void File::InitializeDefaultFile()
+{
+ std::string date = Util::GetCurrentDate();
+ std::string time = Util::GetCurrentTime();
+ std::string uid = Util::CreateUniqueUID();
+ std::string uidMedia = uid;
+ std::string uidInst = uid;
+ std::string uidClass = Util::CreateUniqueUID();
+ std::string uidStudy = Util::CreateUniqueUID();
+ std::string uidSerie = Util::CreateUniqueUID();
+
+ // Meta Element Group Length
+ InsertValEntry("146 ", 0x0002, 0x0000);
+ // Media Storage SOP Class UID (CT Image Storage)
+ InsertValEntry("1.2.840.10008.5.1.4.1.1.2", 0x0002, 0x0002);
+ // Media Storage SOP Instance UID
+ InsertValEntry(uidMedia.c_str(), 0x0002, 0x0003);
+ // Transfer Syntax UID (Explicit VR Little Endian)
+ InsertValEntry("1.2.840.10008.1.2.1 ", 0x0002, 0x0010);
+ // META Implementation Class UID
+ InsertValEntry(uidClass.c_str(), 0x0002, 0x0012);
+ // Source Application Entity Title
+ InsertValEntry("GDCM", 0x0002, 0x0016);
+
+ // Instance Creation Date
+ InsertValEntry(date.c_str(), 0x0008, 0x0012);
+ // Instance Creation Time
+ InsertValEntry(time.c_str(), 0x0008, 0x0013);
+ // SOP Class UID
+ InsertValEntry("1.2.840.10008.5.1.4.1.1.2", 0x0008, 0x0016);
+ // SOP Instance UID
+ InsertValEntry(uidInst.c_str(), 0x0008, 0x0018);
+ // Modality
+ InsertValEntry("CT", 0x0008, 0x0060);
+ // Manufacturer
+ InsertValEntry("GDCM", 0x0008, 0x0070);
+ // Institution Name
+ InsertValEntry("GDCM", 0x0008, 0x0080);
+ // Institution Address
+ InsertValEntry("http://www-creatis.insa-lyon.fr/Public/Gdcm", 0x0008, 0x0081);
+
+ // Patient's Name
+ InsertValEntry("GDCM", 0x0010, 0x0010);
+ // Patient ID
+ InsertValEntry("GDCMID", 0x0010, 0x0020);
+
+ // Study Instance UID
+ InsertValEntry(uidStudy.c_str(), 0x0020, 0x000d);
+ // Series Instance UID
+ InsertValEntry(uidSerie.c_str(), 0x0020, 0x000e);
+ // StudyID
+ InsertValEntry("1", 0x0020, 0x0010);
+ // SeriesNumber
+ InsertValEntry("1", 0x0020, 0x0011);
+
+ // Samples per pixel 1 or 3
+ InsertValEntry("1", 0x0028, 0x0002);
+ // photochromatic interpretation
+ InsertValEntry("MONOCHROME1", 0x0028, 0x0004);
+ // nbRows
+ InsertValEntry("0", 0x0028, 0x0010);
+ // nbCols
+ InsertValEntry("0", 0x0028, 0x0011);
+ // BitsAllocated 8 or 12 or 16
+ InsertValEntry("8", 0x0028, 0x0100);
+ // BitsStored <= BitsAllocated
+ InsertValEntry("8", 0x0028, 0x0101);
+ // HighBit <= BitsAllocated - 1
+ InsertValEntry("7", 0x0028, 0x0102);
+ // Pixel Representation 0(unsigned) or 1(signed)
+ InsertValEntry("0", 0x0028, 0x0103);
+
+ // default value
+ // Special case this is the image (not a string)
+ GrPixel = 0x7fe0;
+ NumPixel = 0x0010;
+ InsertBinEntry(0, 0, GrPixel, NumPixel);
+}
+
+//-----------------------------------------------------------------------------
+// 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"
+ ReadAndSkipEncapsulatedBasicOffsetTable();
+
+ // 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;
+ while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) )
+ {
+ // 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();
+
+ uint32_t nbRleSegments = ReadInt32();
+ if ( nbRleSegments > 16 )
+ {
+ // There should be at most 15 segments (refer to RLEFrame class)
+ gdcmWarningMacro( "Too many segments.");
+ }