#include "gdcmFileDerivation.h"
#include "gdcmFile.h"
#include "gdcmAttribute.h"
#include "gdcmUIDGenerator.h"
#include <vector>
#include <string>
namespace gdcm
{
struct CodeDefinition
{
const char *CodingSchemeDesignator;
unsigned int CodeValue;
const char *CodeMeaning;
};
static const CodeDefinition SourceImagePurposesofReference[] = {
{"DCM",121320,"Uncompressed predecessor"},
{"DCM",121321,"Mask image for image processing operation"},
{"DCM",121322,"Source image for image processing operation"},
{"DCM",121329,"Source image for montage"},
{"DCM",121330,"Lossy compressed predecessor"},
{nullptr,0,nullptr} };
static const CodeDefinition ImageDerivation[] = {
{ "DCM",113040,"Lossy Compression" },
{ "DCM",113041,"Apparent Diffusion Coefficient" },
{ "DCM",113042,"Pixel by pixel addition" },
{ "DCM",113043,"Diffusion weighted" },
{ "DCM",113044,"Diffusion Anisotropy" },
{ "DCM",113045,"Diffusion Attenuated" },
{ "DCM",113046,"Pixel by pixel division" },
{ "DCM",113047,"Pixel by pixel mask" },
{ "DCM",113048,"Pixel by pixel Maximum" },
{ "DCM",113049,"Pixel by pixel mean" },
{ "DCM",113050,"Metabolite Maps from spectroscopy data" },
{ "DCM",113051,"Pixel by pixel Minimum" },
{ "DCM",113052,"Mean Transit Time" },
{ "DCM",113053,"Pixel by pixel multiplication" },
{ "DCM",113054,"Negative Enhancement Integral" },
{ "DCM",113055,"Regional Cerebral Blood Flow" },
{ "DCM",113056,"Regional Cerebral Blood Volume" },
{ "DCM",113057,"R-Coefficient Map" },
{ "DCM",113058,"Proton Density map" },
{ "DCM",113059,"Signal Change Map" },
{ "DCM",113060,"Signal to Noise Map" },
{ "DCM",113061,"Standard Deviation" },
{ "DCM",113062,"Pixel by pixel subtraction" },
{ "DCM",113063,"T1 Map" },
{ "DCM",113064,"T2* Map" },
{ "DCM",113065,"T2 Map" },
{ "DCM",113066,"Time Course of Signal" },
{ "DCM",113067,"Temperature encoded" },
{ "DCM",113068,"Student's T-Test" },
{ "DCM",113069,"Time To Peak map" },
{ "DCM",113070,"Velocity encoded" },
{ "DCM",113071,"Z-Score Map" },
{ "DCM",113072,"Multiplanar reformatting" },
{ "DCM",113073,"Curved multiplanar reformatting" },
{ "DCM",113074,"Volume rendering" },
{ "DCM",113075,"Surface rendering" },
{ "DCM",113076,"Segmentation" },
{ "DCM",113077,"Volume editing" },
{ "DCM",113078,"Maximum intensity projection" },
{ "DCM",113079,"Minimum intensity projection" },
{ "DCM",113085,"Spatial resampling" },
{ "DCM",113086,"Edge enhancement" },
{ "DCM",113087,"Smoothing" },
{ "DCM",113088,"Gaussian blur" },
{ "DCM",113089,"Unsharp mask" },
{ "DCM",113090,"Image stitching" },
{nullptr,0,nullptr} };
static const CodeDefinition PurposeOfReferencetoAlternateRepresentation[] = {
{ "DCM",121324,"Source image" },
{ "DCM",121325,"Lossy compressed image" },
{ "DCM",121326,"Alternate SOP Class instance" },
{ "DCM",121327,"Full fidelity image" },
{ "DCM",121328,"Alternate Photometric Interpretation image" },
{nullptr,0,nullptr} };
class FileDerivationInternals
{
public:
FileDerivationInternals():References(),DerivationDescription()
{}
std::vector< std::pair< std::string, std::string > > References;
unsigned int DerivationCodeSequenceCodeValue{0};
unsigned int PurposeOfReferenceCodeSequenceCodeValue{0};
std::string DerivationDescription;
bool AppendDerivationHistory{false};
};
FileDerivation::FileDerivation():F(new File),Internals(new FileDerivationInternals)
{
}
FileDerivation::~FileDerivation()
{
delete Internals;
}
const CodeDefinition * GetCodeDefinition( unsigned int codevalue, const CodeDefinition list[] )
{
const CodeDefinition * cds = list;
while( cds->CodeMeaning && cds->CodeValue != codevalue )
{
++cds;
}
if( cds->CodeValue )
return cds;
return nullptr;
}
void FileDerivation::SetDerivationDescription( const char *dd )
{
this->Internals->DerivationDescription = dd;
}
void FileDerivation::SetDerivationCodeSequenceCodeValue(unsigned int codevalue)
{
this->Internals->DerivationCodeSequenceCodeValue = codevalue;
}
void FileDerivation::SetPurposeOfReferenceCodeSequenceCodeValue(unsigned int codevalue)
{
this->Internals->PurposeOfReferenceCodeSequenceCodeValue = codevalue;
}
bool FileDerivation::AddReference(const char *referencedsopclassuid, const char *referencedsopinstanceuid)
{
if( !UIDGenerator::IsValid(referencedsopclassuid) )
{
return false;
}
if( !UIDGenerator::IsValid(referencedsopinstanceuid) )
{
return false;
}
Internals->References.emplace_back( referencedsopclassuid, referencedsopinstanceuid );
return true;
}
void FileDerivation::SetAppendDerivationHistory(bool b)
{
Internals->AppendDerivationHistory = b;
}
bool FileDerivation::AddDerivationDescription()
{
File &file = GetFile();
DataSet &ds = file.GetDataSet();
if( !this->Internals->DerivationDescription.empty() )
{
Attribute<0x0008,0x2111> at1;
at1.SetValue( this->Internals->DerivationDescription.c_str() );
ds.Replace( at1.GetAsDataElement() );
}
const Tag sisq(0x8,0x9215);
SmartPointer<SequenceOfItems> sqi;
sqi = new SequenceOfItems;
if( Internals->AppendDerivationHistory )
{
if( ds.FindDataElement( sisq ) )
sqi = ds.GetDataElement( sisq ).GetValueAsSQ();
}
sqi->SetLengthToUndefined();
Item item;
item.SetVLToUndefined();
DataSet &subds3 = item.GetNestedDataSet();
unsigned int codevalue = this->Internals->DerivationCodeSequenceCodeValue;
const CodeDefinition *cd = GetCodeDefinition( codevalue, ImageDerivation );
if ( !cd )
{
return false;
}
std::ostringstream os;
os << cd->CodeValue;
Attribute<0x0008,0x0100> at1;
at1.SetValue( os.str() );
subds3.Replace( at1.GetAsDataElement() );
Attribute<0x0008,0x0102> at2;
at2.SetValue( cd->CodingSchemeDesignator );
subds3.Replace( at2.GetAsDataElement() );
Attribute<0x0008,0x0104> at3;
at3.SetValue( cd->CodeMeaning );
subds3.Replace( at3.GetAsDataElement() );
sqi->AddItem( item );
DataElement de( sisq );
de.SetVR( VR::SQ );
de.SetValue( *sqi );
de.SetVLToUndefined();
ds.Replace( de );
return true;
}
bool FileDerivation::AddSourceImageSequence()
{
File &file = GetFile();
DataSet &ds = file.GetDataSet();
const Tag sisq(0x8,0x2112);
SmartPointer<SequenceOfItems> sqi;
sqi = new SequenceOfItems;
if( ds.FindDataElement( sisq ) )
{
sqi = ds.GetDataElement( sisq ).GetValueAsSQ();
}
sqi->SetLengthToUndefined();
if( !Internals->AppendDerivationHistory && sqi->GetNumberOfItems() )
{
gdcmWarningMacro( "Do not support appending Referenced Image" );
return false;
}
std::vector< std::pair< std::string, std::string > >::const_iterator it =
Internals->References.begin();
for( ; it != Internals->References.end(); ++it )
{
Item item1;
item1.SetVLToUndefined();
DataSet &subds = item1.GetNestedDataSet();
{
Attribute<0x8,0x1150> sopinstanceuid;
sopinstanceuid.SetValue( it->first );
subds.Replace( sopinstanceuid.GetAsDataElement() );
Attribute<0x8,0x1155> sopclassuid;
sopclassuid.SetValue( it->second );
subds.Replace( sopclassuid.GetAsDataElement() );
}
if( !AddPurposeOfReferenceCodeSequence(subds) )
{
return false;
}
sqi->AddItem( item1 );
}
DataElement de( sisq);
de.SetVR( VR::SQ );
de.SetValue( *sqi );
de.SetVLToUndefined();
ds.Replace( de );
return true;
}
bool FileDerivation::AddPurposeOfReferenceCodeSequence(DataSet &subds)
{
const Tag prcs(0x0040,0xa170);
if( !subds.FindDataElement( prcs) )
{
SequenceOfItems *sqi2 = new SequenceOfItems;
DataElement de( prcs );
de.SetVR( VR::SQ );
de.SetValue( *sqi2 );
de.SetVLToUndefined();
subds.Insert( de );
}
SmartPointer<SequenceOfItems> sqi = subds.GetDataElement( prcs ).GetValueAsSQ();
sqi->SetLengthToUndefined();
if( !sqi->GetNumberOfItems() )
{
Item item; item.SetVLToUndefined();
sqi->AddItem( item );
}
Item &item2 = sqi->GetItem(1);
DataSet &subds2 = item2.GetNestedDataSet();
unsigned int codevalue = this->Internals->PurposeOfReferenceCodeSequenceCodeValue;
const CodeDefinition *cd = GetCodeDefinition( codevalue, SourceImagePurposesofReference );
if( !cd )
{
cd = GetCodeDefinition( codevalue, PurposeOfReferencetoAlternateRepresentation );
}
if (!cd)
{
return false;
}
std::ostringstream os;
os << cd->CodeValue;
Attribute<0x0008,0x0100> at1;
at1.SetValue( os.str() );
subds2.Replace( at1.GetAsDataElement() );
Attribute<0x0008,0x0102> at2;
at2.SetValue( cd->CodingSchemeDesignator );
subds2.Replace( at2.GetAsDataElement() );
Attribute<0x0008,0x0104> at3;
at3.SetValue( cd->CodeMeaning );
subds2.Replace( at3.GetAsDataElement() );
return true;
}
bool FileDerivation::Derive()
{
File &file = GetFile();
DataSet &ds = file.GetDataSet();
{
Attribute<0x0008,0x0008> at3;
static const CSComp values[] = {"DERIVED","SECONDARY"};
at3.SetValues( values, 2, true ); if( ds.FindDataElement( at3.GetTag() ) )
{
const DataElement &de = ds.GetDataElement( at3.GetTag() );
if( !de.IsEmpty() )
at3.SetFromDataElement( de );
at3.SetValue( 0, values[0] );
}
ds.Replace( at3.GetAsDataElement() );
}
bool b = AddSourceImageSequence();
if( !b )
{
gdcmDebugMacro( "Could not AddSourceImageSequence" );
return false;
}
b = AddDerivationDescription();
if( !b )
{
gdcmDebugMacro( "Could not AddDerivationDescription" );
return false;
}
return true;
}
}