📄 gdcmfilehelper.cxx
字号:
if ( nbBitsStored == 0 || nbBitsStored > nbBitsAllocated )
{
os.str("");
os << nbBitsAllocated;
CopyMandatoryEntry(0x0028,0x0101,os.str());
gdcmWarningMacro("(0028,0101) changed from "
<< nbBitsStored << " to " << nbBitsAllocated
<< " for consistency purpose" );
nbBitsStored = nbBitsAllocated;
}
// check 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored'
int highBitPosition = FileInternal->GetHighBitPosition();
if ( highBitPosition == 0 ||
highBitPosition > nbBitsAllocated-1 ||
highBitPosition < nbBitsStored-1 )
{
os.str("");
os << nbBitsStored - 1;
CopyMandatoryEntry(0x0028,0x0102,os.str());
gdcmWarningMacro("(0028,0102) changed from "
<< highBitPosition << " to " << nbBitsAllocated-1
<< " for consistency purpose");
}
std::string pixelSpacing = FileInternal->GetEntryValue(0x0028,0x0030);
if ( pixelSpacing == GDCM_UNFOUND )
{
pixelSpacing = "1.0\\1.0";
// if missing, Pixel Spacing forced to "1.0\1.0"
CopyMandatoryEntry(0x0028,0x0030,pixelSpacing);
}
std::string imageOrientationPatient = FileInternal->GetEntryValue(0x0020,0x0037);
if ( imageOrientationPatient == GDCM_UNFOUND )
{
imageOrientationPatient = "1\\0\\0\\0\\1\\0";
CopyMandatoryEntry(0x0020,0x0037,imageOrientationPatient);
}
// 'Imager Pixel Spacing' : defaulted to 'Pixel Spacing'
// --> This one is the *legal* one !
// FIXME : we should write it only when we are *sure* the image comes from
// an imager (see also 0008,0x0064)
CheckMandatoryEntry(0x0018,0x1164,pixelSpacing);
// Samples Per Pixel (type 1) : default to grayscale
CheckMandatoryEntry(0x0028,0x0002,"1");
// --- Check UID-related Entries ---
// If 'SOP Class UID' exists ('true DICOM' image)
// we create the 'Source Image Sequence' SeqEntry
// to hold informations about the Source Image
ValEntry *e_0008_0016 = FileInternal->GetValEntry(0x0008, 0x0016);
if ( e_0008_0016 )
{
// Make sure 0008,0016 & 0002,0002 are always consistant whatever user says...
ValEntry *e_0002_0002 = FileInternal->GetValEntry(0x0002, 0x0002);
e_0002_0002->SetValue( e_0008_0016->GetValue() );
// Create 'Source Image Sequence' SeqEntry
SeqEntry *sis = new SeqEntry (
Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) );
SQItem *sqi = new SQItem(1);
// (we assume 'SOP Instance UID' exists too)
// create 'Referenced SOP Class UID'
ValEntry *e_0008_1150 = new ValEntry(
Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1150) );
e_0008_1150->SetValue( e_0008_0016->GetValue());
sqi->AddEntry(e_0008_1150);
// create 'Referenced SOP Instance UID'
ValEntry *e_0008_0018 = FileInternal->GetValEntry(0x0008, 0x0018);
// Make sure 0008,0018 & 0002,0003 are always consistant whatever user says...
ValEntry *e_0002_0003 = FileInternal->GetValEntry(0x0002, 0x0003);
e_0002_0003->SetValue( e_0008_0018->GetValue() );
ValEntry *e_0008_1155 = new ValEntry(
Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1155) );
e_0008_1155->SetValue( e_0008_0018->GetValue());
sqi->AddEntry(e_0008_1155);
sis->AddSQItem(sqi,1);
// temporarily replaces any previous 'Source Image Sequence'
Archive->Push(sis);
// 'Image Type' (The written image is no longer an 'ORIGINAL' one)
ValEntry *e_0008_0008 = FileInternal->GetValEntry(0x0008, 0x0008);
std::string imagetype = "DERIVED\\PRIMARY";
// Make sure to preserved information from element 0008,0008, simply replace
// comp #1 of Image Type with 'DERIVED', as gdcm is always deriving image
if( e_0008_0008 )
{
std::string s = e_0008_0008->GetValue();
if( !s.empty() )
{
std::vector<std::string> tokens;
gdcm::Util::Tokenize( s, tokens, "\\");
// Make sure we can find at least 2 names...
if( tokens.size() >= 2 )
{
itksys_ios::ostringstream os2;
for( std::vector<std::string>::const_iterator it = tokens.begin();
it != tokens.end(); ++it)
{
if( it == tokens.begin() )
{
// Mark it DERIVED
os2 << "DERIVED";
}
else
{
os2 << "\\";
os2 << *it;
}
}
imagetype = os.str();
}
}
}
CopyMandatoryEntry(0x0008,0x0008,imagetype);
}
else
{
ValEntry *e_0002_0002 = FileInternal->GetValEntry(0x0002, 0x0002);
if( e_0002_0002 )
{
e_0008_0016 = new ValEntry(
Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0016) );
e_0008_0016 ->SetValue( e_0002_0002->GetValue() );
ValEntry *e_0008_0018 = FileInternal->GetValEntry(0x0008, 0x0018);
if( e_0008_0018 )
{
e_0008_0018->SetValue(
FileInternal->GetValEntry(0x0002,0x0003)->GetValue() );
}
Archive->Push(e_0008_0016);
}
else
{
// There was no 'SOP Class UID' nor 'Media Storage SOP UID'
// the source image was NOT a true Dicom one.
// We consider the image is a 'Secondary Capture' one
// SOP Class UID
e_0008_0016 = new ValEntry(
Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0016) );
// [Secondary Capture Image Storage]
e_0008_0016 ->SetValue("1.2.840.10008.5.1.4.1.1.7");
Archive->Push(e_0008_0016);
}
}
// ---- The user will never have to take any action on the following ----
// new value for 'SOP Instance UID'
//ValEntry *e_0008_0018 = new ValEntry(
// Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0018) );
//e_0008_0018->SetValue( Util::CreateUniqueUID() );
//Archive->Push(e_0008_0018);
CheckMandatoryEntry(0x0008,0x0018,sop);
// Instance Creation Date
const std::string &date = Util::GetCurrentDate();
CopyMandatoryEntry(0x0008,0x0012,date);
// Instance Creation Time
const std::string &time = Util::GetCurrentTime();
CopyMandatoryEntry(0x0008,0x0013,time);
// Study Date
CheckMandatoryEntry(0x0008,0x0020,date);
// Study Time
CheckMandatoryEntry(0x0008,0x0030,time);
// Accession Number
//CopyMandatoryEntry(0x0008,0x0050,"");
CheckMandatoryEntry(0x0008,0x0050,"");
// ----- Add Mandatory Entries if missing ---
// Entries whose type is 1 are mandatory, with a mandatory value
// Entries whose type is 1c are mandatory-inside-a-Sequence,
// with a mandatory value
// Entries whose type is 2 are mandatory, with an optional value
// Entries whose type is 2c are mandatory-inside-a-Sequence,
// with an optional value
// Entries whose type is 3 are optional
// 'Study Instance UID'
// Keep the value if exists
// The user is allowed to create his own Study,
// keeping the same 'Study Instance UID' for various images
// The user may add images to a 'Manufacturer Study',
// adding new Series to an already existing Study
CheckMandatoryEntry(0x0020,0x000d,Util::CreateUniqueUID());
// 'Serie Instance UID'
// Keep the value if exists
// The user is allowed to create his own Series,
// keeping the same 'Serie Instance UID' for various images
// The user shouldn't add any image to a 'Manufacturer Serie'
// but there is no way no to prevent him for doing that
CheckMandatoryEntry(0x0020,0x000e,Util::CreateUniqueUID());
// Study ID
CheckMandatoryEntry(0x0020,0x0010,"");
// Series Number
CheckMandatoryEntry(0x0020,0x0011,"");
// Instance Number
CheckMandatoryEntry(0x0020,0x0013,"");
// Patient Orientation
// Can be computed from (0020|0037) : Image Orientation (Patient)
gdcm::Orientation o;
std::string ori = o.GetOrientation ( FileInternal );
if (ori != "\\" && ori != GDCM_UNFOUND)
CheckMandatoryEntry(0x0020,0x0020,ori);
else
CheckMandatoryEntry(0x0020,0x0020,"");
// Modality : if missing we set it to 'OTher'
CheckMandatoryEntry(0x0008,0x0060,"OT");
// Conversion Type: if missing we set it to 'SYN'
CheckMandatoryEntry(0x0008,0x0064,"SYN");
// Manufacturer : if missing we set it to 'GDCM Factory'
CheckMandatoryEntry(0x0008,0x0070,"GDCM Factory");
// Institution Name : if missing we set it to 'GDCM Hospital'
CheckMandatoryEntry(0x0008,0x0080,"GDCM Hospital");
// Patient's Name : if missing, we set it to 'GDCM^Patient'
CheckMandatoryEntry(0x0010,0x0010,"GDCM^Patient");
// Patient ID : 'type 2' entry but some DICOM implementation really needs it.
CheckMandatoryEntry(0x0010,0x0020,"GDCM ID");
// Patient's Birth Date : 'type 2' entry -> must exist, value not mandatory
CheckMandatoryEntry(0x0010,0x0030,"");
// Patient's Sex :'type 2' entry -> must exist, value not mandatory
CheckMandatoryEntry(0x0010,0x0040,"");
// Referring Physician's Name :'type 2' entry -> must exist, value not mandatory
CheckMandatoryEntry(0x0008,0x0090,"");
}
void FileHelper::CheckMandatoryEntry(uint16_t group,uint16_t elem,std::string value)
{
ValEntry *ve = FileInternal->GetValEntry(group, elem);
if ( !ve)
{
ve = new ValEntry(
Global::GetDicts()->GetDefaultPubDict()->GetEntry(group, elem) );
ve->SetValue( value );
Archive->Push(ve);
}
}
void FileHelper::CopyMandatoryEntry(uint16_t group,uint16_t elem,std::string value)
{
ValEntry *entry = CopyValEntry(group,elem);
entry->SetValue(value);
Archive->Push(entry);
}
/**
* \brief Restore in the File the initial group 0002
*/
void FileHelper::RestoreWriteMandatory()
{
// group 0002 may be pushed out for ACR-NEMA writting purposes
Archive->Restore(0x0002,0x0000);
Archive->Restore(0x0002,0x0001);
Archive->Restore(0x0002,0x0002);
Archive->Restore(0x0002,0x0003);
Archive->Restore(0x0002,0x0010);
Archive->Restore(0x0002,0x0012);
Archive->Restore(0x0002,0x0013);
Archive->Restore(0x0002,0x0016);
Archive->Restore(0x0002,0x0100);
Archive->Restore(0x0002,0x0102);
Archive->Restore(0x0008,0x0012);
Archive->Restore(0x0008,0x0013);
Archive->Restore(0x0008,0x0016);
Archive->Restore(0x0008,0x0018);
Archive->Restore(0x0008,0x0060);
Archive->Restore(0x0008,0x0070);
Archive->Restore(0x0008,0x0080);
Archive->Restore(0x0008,0x0090);
Archive->Restore(0x0008,0x2112);
Archive->Restore(0x0010,0x0010);
Archive->Restore(0x0010,0x0030);
Archive->Restore(0x0010,0x0040);
Archive->Restore(0x0020,0x000d);
Archive->Restore(0x0020,0x000e);
}
//-----------------------------------------------------------------------------
// Private
/**
* \brief Factorization for various forms of constructors.
*/
void FileHelper::Initialize()
{
UserFunction = 0;
KeepMediaStorageSOPClassUID = false;
WriteMode = WMODE_RAW;
//WriteType = ExplicitVR;
WriteType = Unknown;
PixelReadConverter = new PixelReadConvert;
PixelWriteConverter = new PixelWriteConvert;
Archive = new DocEntryArchive( FileInternal );
}
/**
* \brief Reads/[decompresses] the pixels,
* *without* making RGB from Palette Colors
* @return the pixels area, whatever its type
* (uint8_t is just for prototyping : feel free to Cast it)
*/
uint8_t *FileHelper::GetRaw()
{
PixelReadConverter->SetUserFunction( UserFunction );
uint8_t *raw = PixelReadConverter->GetRaw();
if ( ! raw )
{
// The Raw image migth not be loaded yet:
std::ifstream *fp = FileInternal->OpenFile();
PixelReadConverter->ReadAndDecompressPixelData( fp );
if ( fp )
FileInternal->CloseFile();
raw = PixelReadConverter->GetRaw();
if ( ! raw )
{
gdcmWarningMacro( "Read/decompress of pixel data apparently went wrong.");
return 0;
}
}
return raw;
}
//-----------------------------------------------------------------------------
/**
* \brief Prints the common part of ValEntry, BinEntry, SeqEntry
* @param os ostream we want to print in
* @param indent (unused)
*/
void FileHelper::Print(std::ostream &os, std::string const &)
{
FileInternal->SetPrintLevel(PrintLevel);
FileInternal->Print(os);
if ( FileInternal->IsReadable() )
{
PixelReadConverter->SetPrintLevel(PrintLevel);
PixelReadConverter->Print(os);
}
}
//-----------------------------------------------------------------------------
} // end namespace gdcm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -