| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894 | 
#include "ctkDICOMDataset.h"#include <dctk.h>#include <dcostrmb.h>#include <dcistrmb.h>#include <stdexcept>class ctkDICOMDatasetPrivate{  public:    ctkDICOMDatasetPrivate() {}    QString m_SpecificCharacterSet;    bool m_DICOMDataSetInitialized;    static const QScopedPointer<const DcmDataDictionary> s_Dictionary;    DcmDataset* m_DcmDataset;};const QScopedPointer<const DcmDataDictionary> ctkDICOMDatasetPrivate::s_Dictionary(new DcmDataDictionary(OFTrue, OFTrue));// = QScopedPointer<const DcmDataDictionary>(new DcmDataDictionary(OFTrue, OFTrue));ctkDICOMDataset::ctkDICOMDataset() :d_ptr(new ctkDICOMDatasetPrivate){  Q_D(ctkDICOMDataset);  d->m_DICOMDataSetInitialized = false;  d->m_DcmDataset = this;}ctkDICOMDataset::~ctkDICOMDataset() {  Q_D(ctkDICOMDataset);  if(d->m_DcmDataset != this)  {    delete d->m_DcmDataset;  }}void ctkDICOMDataset::InitializeFromDataset(DcmDataset* dataset){  Q_D(ctkDICOMDataset);  if(d->m_DcmDataset != this)  {    delete d->m_DcmDataset;    d->m_DcmDataset = NULL;  }  if (dataset)  {    d->m_DcmDataset=dataset;    if (!d->m_DICOMDataSetInitialized)    {      d->m_DICOMDataSetInitialized = true;      // remember "specific character set" tag for conversion of strings to the right encoding      //std::cerr << "** " << (void*)this << " ctkDICOMDataset: Initialized DcmDataset" << std::endl;      if ( CopyElement( dataset, DCM_SpecificCharacterSet, 3 ) )      {        OFString encoding;        if ( CheckCondition( findAndGetOFString(DCM_SpecificCharacterSet, encoding) ) )        {          d->m_SpecificCharacterSet = encoding.c_str();        }        else        {          std::cerr << "Some implementation error in DCMTK. We put something into a box and now the box is empty. This is not ok." << std::endl;          //throw std::logic_error("Some implementation error in DCMTK. We put something into a box and now the box is empty. This is not ok.");        }      }      if (d->m_SpecificCharacterSet.isEmpty())      {        /**          see Bug # 6458:          There are cases, where different studies of the same person get encoded both with and without the SpecificCharacterSet attribute set.          DICOM says: default is ASCII / ISO_IR 6 / ISO 646          Since we experienced such mixed data, we supplement missing characterset information with the ISO_IR 100 / Latin1 character set.          Since Latin1 is a superset of ASCII, this will not cause problems. PLUS in most cases (Europe) we will guess right and suppress          "double patients" in applications.        */        SetElementAsString( DCM_SpecificCharacterSet, "ISO_IR 100" );      }    }  }}void ctkDICOMDataset::InitializeFromFile(const QString& filename,const E_TransferSyntax readXfer,                    const E_GrpLenEncoding groupLength,                    const Uint32 maxReadLength,                    const E_FileReadMode readMode){  Q_D(ctkDICOMDataset);  DcmDataset *dataset;    DcmFileFormat fileformat;  OFCondition status = fileformat.loadFile(filename.toAscii().data(), readXfer, groupLength, readMode);  dataset = fileformat.getAndRemoveDataset();  if (!status.good())  {    qDebug() << "Could not load " << filename << "\nDCMTK says: " << status.text();    delete dataset;    return;  }  InitializeFromDataset(dataset);}void ctkDICOMDataset::Serialize(){  // store content of current DcmDataset (our parent) as QByteArray into m_ctkDICOMDataset  Uint32 buffersize = 1024*1024; // reserve 1MB  char* writebuffer = new char[buffersize];  // write into buffer  DcmOutputBufferStream dcmbuffer(writebuffer, buffersize);  DcmDataset::transferInit();  OFCondition condition = DcmDataset::write(dcmbuffer, EXS_LittleEndianImplicit, EET_UndefinedLength, NULL );  DcmDataset::transferEnd();  if ( condition.bad() )  {    std::cerr << "Could not DcmDataset::write(..): " << condition.text() << std::endl;  }  // get written contents of buffer  offile_off_t datasetsize = 0;  void* readbuffer = NULL;  dcmbuffer.flushBuffer(readbuffer, datasetsize);  //std::cerr << "** " << (void*)this << " ctkDICOMDataset: Serializing Dataset into " << datasetsize << " bytes" << std::endl;  // construct Qt type from that contents  QByteArray qtArray = QByteArray::fromRawData( static_cast<const char*>(readbuffer), datasetsize );  //std::cerr << "** Buffer size: " << qtArray.size() << std::endl;  QString stringbuffer = QString::fromAscii(qtArray.toBase64());  //std::cerr << "** String of size " << stringbuffer.size() << " looks like this:\n" << stringbuffer.toStdString() << std::endl << std::endl;  this->SetStoredSerialization( stringbuffer );  delete[] writebuffer;}void ctkDICOMDataset::MarkForInitialization(){  Q_D(ctkDICOMDataset);  d->m_DICOMDataSetInitialized = false;}void ctkDICOMDataset::EnsureDcmDataSetIsInitialized() const{  const_cast<ctkDICOMDataset*>(this)->Deserialize();}void ctkDICOMDataset::Deserialize(){  Q_D(ctkDICOMDataset);  // read attribute m_ctkDICOMDataset  // construct a DcmDataset from it  // calls InitializeData(DcmDataset*)  // this method can be called both from sub-classes when they get the InitializeData signal from the persistence framework  // and from EnsureDcmDataSetIsInitialized() when a GetElement.. or SetElement.. method is called.  if (d->m_DICOMDataSetInitialized) return; // only need to do this once  QString stringbuffer = this->GetStoredSerialization();  if ( stringbuffer.isEmpty() )  {    d->m_DICOMDataSetInitialized = true;    return; // TODO nicer: hold three states: newly created / loaded but not initialized / restored from DB  }  //std::cerr << "** " << (void*)this << " ctkDICOMDataset: Deserialize Dataset from string of size " << stringbuffer.size() << "\n" << stringbuffer.toStdString() << std::endl;  QByteArray qtArray = QByteArray::fromBase64( stringbuffer.toAscii() );  //std::cerr << "** " << (void*)this << " ctkDICOMDataset: Deserialize Dataset from byte array of size " << qtArray.size() << std::endl;  DcmInputBufferStream dcmbuffer;  dcmbuffer.setBuffer( qtArray.data(), qtArray.size() );  //std::cerr << "** Buffer state: " << dcmbuffer.status().code() << " " <<  dcmbuffer.good() << " " << dcmbuffer.eos() << " tell " << dcmbuffer.tell() << " avail " << dcmbuffer.avail() << std::endl;  DcmDataset dataset;  dataset.transferInit();  //std::cerr << "** Dataset state: " << dataset.transferState() << std::endl << std::endl;  OFCondition condition = dataset.read( dcmbuffer, EXS_LittleEndianImplicit );  dataset.transferEnd();  // do this in all cases, even when reading reported an error  this->InitializeFromDataset(&dataset);  if ( condition.bad() )  {    std::cerr << "** Condition code of Dataset::read() is " << condition.code() << std::endl;    std::cerr << "** Buffer state: " << dcmbuffer.status().code() << " " <<  dcmbuffer.good() << " " << dcmbuffer.eos() << " tell " << dcmbuffer.tell() << " avail " << dcmbuffer.avail() << std::endl;    std::cerr << "** Dataset state: " << (int)dataset.transferState() << std::endl;    std::cerr << std::string("Could not DcmDataset::read(..): ") + condition.text() << std::endl;    //throw std::invalid_argument( std::string("Could not DcmDataset::read(..): ") + condition.text() );  }}DcmDataset& ctkDICOMDataset::GetDcmDataset() const{  const Q_D(ctkDICOMDataset);  return *d->m_DcmDataset;}OFCondition ctkDICOMDataset::findAndGetElement(const DcmTag& tag, DcmElement*& element, const OFBool searchIntoSub) const{  // this one const_cast allows us to declare quite a lot of methods nicely with const  return GetDcmDataset().findAndGetElement(tag, element, searchIntoSub);}OFCondition ctkDICOMDataset::findAndGetOFString(const DcmTag& tag, OFString& value, const unsigned long pos, const OFBool searchIntoSub) const{  // this second const_cast allows us to declare quite a lot of methods nicely with const  return GetDcmDataset().findAndGetOFString(tag, value, pos, searchIntoSub);}bool ctkDICOMDataset::CheckCondition(const OFCondition& condition){  if ( condition.bad() )  {    //std::cerr << "Bad return code (" << condition.code() << "): " << condition.text() << std::endl;  }  return condition.good();}bool ctkDICOMDataset::CopyElement( DcmDataset* dataset, const DcmTagKey& tag, int type ){  switch (type)  {    case 0x1:    case 0x1C:    case 0x2:    case 0x2C:    case 0x3:      // these are ok      break;    default:      // nothing else is ok      std::cerr << "Unknown attribute type. Cannot process call to ExtractElement " << TagKey(tag).toStdString() << std::endl;      return false;  }  bool missing(false);  bool copied(true);  if (!dataset) return false;  // type 1 or 1C must exist AND have a value  if (!dataset->tagExistsWithValue( tag ))  {    if (type == 0x1 || type == 0x1C) missing = true;  }  // type 2 or 2C must exist but may have an empty value  if (!dataset->tagExists( tag ))  {    if (type == 0x1 || type == 0x1C) missing = true;    if (type == 0x2 || type == 0x2C) missing = true;  }  else  {    // we found this tag    DcmElement* element(NULL);    dataset->findAndGetElement( tag, element, OFFalse, OFTrue ); // OFTrue is important (copies element), DcmDataset takes ownership and deletes elements on its own destruction    if (element)    {      copied = CheckCondition( DcmDataset::insert(element) );    }  }  if (missing)  {    std::cerr << "Tag " << TagKey(tag).toStdString() << " [" << TagDescription(tag).toStdString() << "] of type " << QString("%1").arg(type,0,16).toStdString() << " missing or empty." << std::endl;  }  if (!copied)  {    std::cerr << "Tag " << TagKey(tag).toStdString() << " [" << TagDescription(tag).toStdString() << "] not copied successfully" << std::endl;  }  return !missing && copied;}QString ctkDICOMDataset::Decode( const DcmTag& tag, const OFString& raw ) const{  Q_D(const ctkDICOMDataset);  // decode for types LO, LT, PN, SH, ST, UT  QString vr = TagVR(tag);  if ( !d->m_SpecificCharacterSet.isEmpty()    && (vr == "LO" ||        vr == "LT" ||        vr == "PN" ||        vr == "SH" ||        vr == "ST" ||        vr == "UT" ) )  {    //std::cout << "Decode from encoding " << d->m_SpecificCharacterSet.toStdString() << std::endl;    static QMap<QString, QTextDecoder*> decoders;    static QMap<QString, QString> qtEncodingNamesForDICOMEncodingNames;    if (qtEncodingNamesForDICOMEncodingNames.isEmpty())    {      // runs only once and fills up a map of encoding names that might be named in DICOM files.      // for each encoding we store the name that Qt uses for the same encoding.      // This is because there is not yet a standard naming scheme but lots of aliases      // out in the real world: e.g. http://www.openi18n.org/subgroups/sa/locnameguide/final/CodesetAliasTable.html                                              //    DICOM        Qt      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 192", "UTF-8");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 100", "ISO-8859-1");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 101", "ISO-8859-2");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 109", "ISO-8859-3");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 110", "ISO-8859-4");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 144", "ISO-8859-5");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 127", "ISO-8859-6");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 126", "ISO-8859-7");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 138", "ISO-8859-8");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 148", "ISO-8859-9");      qtEncodingNamesForDICOMEncodingNames.insert("ISO_IR 179", "ISO-8859-13");      qtEncodingNamesForDICOMEncodingNames.insert("ISO 2022 IR 13", "jisx0201*-0");      // use all names that Qt knows by itself      foreach( QByteArray c, QTextCodec::availableCodecs() )      {        qtEncodingNamesForDICOMEncodingNames.insert( c.constData(), c.constData() );      }    }    if ( qtEncodingNamesForDICOMEncodingNames.contains(d->m_SpecificCharacterSet) )    {      QString encodingName( qtEncodingNamesForDICOMEncodingNames[d->m_SpecificCharacterSet] );      if ( !decoders.contains( encodingName ) )      {        QTextCodec* codec = QTextCodec::codecForName( encodingName.toAscii() );        if (!codec)        {          std::cerr << "Could not create QTextCodec object for '" << encodingName.toStdString() << "'. Using default encoding instead." << std::endl;          decoders.insert( encodingName, QTextCodec::codecForCStrings()->makeDecoder() ); // uses Latin1        }        else        {          // initialize a QTextDecoder for given encoding          decoders.insert( encodingName, codec->makeDecoder() );          // We are responsible for deleting the QTextDecoder objects          // created by makeDecoder(). BUT as these objects are stored          // in a static map that lives until application end AND          // nothing application relevant happens during their          // destruction, we just let them be destructed by C++ on          // application exit.          // Any potential leaks that are found by this behavior can          // be suppressed.        }      }      //std::cout << "Decode '" <<  raw.c_str() << "' to '" << decoders[encodingName]->toUnicode( raw.c_str() ).toLocal8Bit().constData() << "'" << std::endl;      return decoders[encodingName]->toUnicode( raw.c_str() );    }    else    {      std::cerr << "DICOM dataset contains some encoding that we never thought we would see(" << d->m_SpecificCharacterSet.toStdString() << "). Using default encoding." << std::endl;    }  }  return QString::fromLatin1(raw.c_str()); // Latin1 is ISO 8859, which is the default character set of DICOM (PS 3.5-2008, Page 18)}OFString ctkDICOMDataset::Encode( const DcmTag& tag, const QString& qstring ) const{  // TODO: respect given character-set when encoding; see Decode()  return OFString( qstring.toLatin1().data() ); // Latin1 is ISO 8859, which is the default character set of DICOM (PS 3.5-2008, Page 18)}    QString ctkDICOMDataset::GetAllElementValuesAsString( const DcmTag& tag ) const{  this->EnsureDcmDataSetIsInitialized();  QStringList qsl;  DcmElement* element(NULL);  findAndGetElement(tag, element);  if (!element) return QString::null;  const unsigned long count = element->getVM(); // value multiplicity  for (unsigned long i = 0; i < count; ++i)  {    OFString s;    if ( CheckCondition( const_cast<ctkDICOMDataset*>(this)->findAndGetOFString(tag, s, i) ) )    {      qsl << Decode( tag, s );    }  }  return qsl.join("|");}QString ctkDICOMDataset::GetElementAsString( const DcmTag& tag, unsigned long pos ) const{  this->EnsureDcmDataSetIsInitialized();  OFString s;  if ( CheckCondition( findAndGetOFString(tag, s, pos) ) )  {    return Decode( tag, s );  }  else  {    return QString::null;  }}QStringList ctkDICOMDataset::GetElementAsStringList( const DcmTag& tag ) const{  this->EnsureDcmDataSetIsInitialized();  QStringList qsl;  DcmElement* element(NULL);  findAndGetElement(tag, element);  if (!element) return qsl;  const unsigned long count = element->getVM(); // value multiplicity  for (unsigned long i = 0; i < count; ++i)  {    qsl << GetElementAsString(tag, i);  }  return qsl;}ctkDICOMPersonName ctkDICOMDataset::GetElementAsPersonName( const DcmTag& tag, unsigned long pos ) const{  this->EnsureDcmDataSetIsInitialized();  DcmElement* element(NULL);  findAndGetElement(tag, element);  DcmPersonName* name = dynamic_cast<DcmPersonName*>(element);  if (!name) return ctkDICOMPersonName(); // invalid  OFString lastName;  OFString firstName;  OFString middleName;  OFString namePrefix;  OFString nameSuffix;  if (CheckCondition( name->getNameComponents(lastName, firstName, middleName, namePrefix, nameSuffix, pos) ) )  {    return ctkDICOMPersonName(      Decode(tag, lastName),      Decode(tag, firstName),      Decode(tag, middleName),      Decode(tag, namePrefix),      Decode(tag, nameSuffix) );  }  else  {    return ctkDICOMPersonName();  }}ctkDICOMPersonNameList ctkDICOMDataset::GetElementAsPersonNameList( const DcmTag& tag ) const{  this->EnsureDcmDataSetIsInitialized();  ctkDICOMPersonNameList qpnl;  DcmElement* element(NULL);  findAndGetElement(tag, element);  if (!element) return qpnl;  const unsigned long count = element->getVM(); // value multiplicity  for (unsigned long i = 0; i < count; ++i)  {    qpnl << GetElementAsPersonName(tag, i);  }  return qpnl;}QDate ctkDICOMDataset::GetElementAsDate( const DcmTag& tag, unsigned long pos ) const{  this->EnsureDcmDataSetIsInitialized();  DcmElement* element(NULL);  findAndGetElement(tag, element);  DcmDate* date = dynamic_cast<DcmDate*>(element);  if (!date) return QDate(); // invalid  OFString ofs;  if (CheckCondition( date->getISOFormattedDate(ofs, pos) ) )  {    QString qs(ofs.c_str());    return QDate::fromString(qs, "yyyy-MM-dd");  }  else  {    return QDate();  }}QTime ctkDICOMDataset::GetElementAsTime( const DcmTag& tag, unsigned long pos ) const{  this->EnsureDcmDataSetIsInitialized();  DcmElement* element(NULL);  findAndGetElement(tag, element);  DcmTime* time = dynamic_cast<DcmTime*>(element);  if (!time) return QTime(); // invalid  OFString ofs;  if (CheckCondition( time->getISOFormattedTime(ofs, pos, OFTrue, OFFalse) ) ) // true (seconds), false (fraction of a second)  {    QString qs(ofs.c_str());    return QTime::fromString(qs, "hh:mm:ss");  }  else  {    return QTime();  }}QDateTime ctkDICOMDataset::GetElementAsDateTime( const DcmTag& tag, unsigned long pos ) const{  this->EnsureDcmDataSetIsInitialized();  DcmElement* element(NULL);  findAndGetElement(tag, element);  DcmDateTime* datetime = dynamic_cast<DcmDateTime*>(element);  if (!datetime) return QDateTime(); // invalid  OFString ofs;  if (CheckCondition( datetime->getISOFormattedDateTime(ofs, pos, OFTrue, OFFalse, OFTrue) ) ) // true (seconds), false (fraction of a second), true (time zone)  {    QString qs(ofs.c_str());    return QDateTime::fromString(qs, "dd-MM-yyy hh:mm:ss");  }  else  {    return QDateTime();  }}double ctkDICOMDataset::GetElementAsDouble( const DcmTag& tag, unsigned long pos ) const{  this->EnsureDcmDataSetIsInitialized();  DcmElement* element(NULL);  findAndGetElement(tag, element);  DcmDecimalString* ds = dynamic_cast<DcmDecimalString*>(element);  if (!ds) throw std::logic_error("Element not found or not a decimal number");  Float64 d;  ds->getFloat64(d, pos);  return d;}long ctkDICOMDataset::GetElementAsInteger( const DcmTag& tag, unsigned long pos ) const{  this->EnsureDcmDataSetIsInitialized();  DcmElement* element(NULL);  findAndGetElement(tag, element);  DcmIntegerString* is = dynamic_cast<DcmIntegerString*>(element);  if (!is) throw std::logic_error("Element not found or not an integer");  Sint32 i;  is->getSint32(i, pos);  return i;}int ctkDICOMDataset::GetElementAsSignedShort( const DcmTag& tag, unsigned long pos ) const // type SS{  this->EnsureDcmDataSetIsInitialized();  DcmElement* element(NULL);  findAndGetElement(tag, element);  DcmSignedShort* ss = dynamic_cast<DcmSignedShort*>(element);  if (!ss) throw std::logic_error("Element not found or not a signed short integer");  Sint16 i;  ss->getSint16(i, pos);  return i;}int ctkDICOMDataset::GetElementAsUnsignedShort( const DcmTag& tag, unsigned long pos ) const // type US{  this->EnsureDcmDataSetIsInitialized();  DcmElement* element(NULL);  findAndGetElement(tag, element);  DcmUnsignedShort* us = dynamic_cast<DcmUnsignedShort*>(element);  if (!us) throw std::logic_error("Element not found or not a unsigned short integer");  Uint16 i;  us->getUint16(i, pos);  return i;}bool ctkDICOMDataset::SetElementAsString( const DcmTag& tag, QString string ){  this->EnsureDcmDataSetIsInitialized();  // TODO: Evaluate DICOM tag for proper encoding (see GetElementAsString())  return CheckCondition( putAndInsertString( tag, string.toLatin1().data() ) );}bool ctkDICOMDataset::SetElementAsStringList( const DcmTag& /*tag*/, QStringList /*stringList*/ ){  this->EnsureDcmDataSetIsInitialized();  // TODO: Find out how this can be implemented with DcmDataset methods; there is no method for  // setting a string at a given position  return false;}bool ctkDICOMDataset::SetElementAsPersonName( const DcmTag& tag, ctkDICOMPersonName personName ){  this->EnsureDcmDataSetIsInitialized();  DcmPersonName* dcmPersonName = new DcmPersonName( tag ); // TODO leak?  if ( CheckCondition( dcmPersonName->putNameComponents(    Encode( tag, personName.lastName() ),    Encode( tag, personName.firstName() ),    Encode( tag, personName.middleName() ),    Encode( tag, personName.namePrefix() ),    Encode( tag, personName.nameSuffix() ) ) ) )  {    return CheckCondition( insert( dcmPersonName ) );  }  return false;}bool ctkDICOMDataset::SetElementAsPersonNameList( const DcmTag& tag, ctkDICOMPersonNameList personNameList ){  this->EnsureDcmDataSetIsInitialized();  // TODO: Find out how this can be implemented with DcmDataset methods; there is no method for  // setting an element at a given position  return false;}bool ctkDICOMDataset::SetElementAsDate( const DcmTag& tag, QDate date ){  this->EnsureDcmDataSetIsInitialized();  OFDate ofDate( date.year(), date.month(), date.day() );  DcmDate* dcmDate = new DcmDate( tag ); // TODO leak?  if ( CheckCondition( dcmDate->setOFDate( ofDate ) ) )  {    return CheckCondition( insert( dcmDate ) );  }  return false;}bool ctkDICOMDataset::SetElementAsTime( const DcmTag& tag, QTime time ){  this->EnsureDcmDataSetIsInitialized();  OFTime ofTime( time.hour(), time.minute(), time.second() );  DcmTime* dcmTime = new DcmTime( tag ); // TODO leak?  if ( CheckCondition( dcmTime->setOFTime( ofTime ) ) )  {    return CheckCondition( insert( dcmTime ) );  }  return false;}bool ctkDICOMDataset::SetElementAsDateTime( const DcmTag& tag, QDateTime dateTime ){  this->EnsureDcmDataSetIsInitialized();  QDate date = dateTime.date();  QTime time = dateTime.time();  OFDateTime ofDateTime;  ofDateTime.setDateTime( date.year(), date.month(), date.day(), time.hour(), time.minute(), time.second() );  DcmDateTime* dcmDateTime = new DcmDateTime( tag ); // TODO leak?  if ( CheckCondition( dcmDateTime->setOFDateTime( ofDateTime ) ) )  {    return CheckCondition( insert( dcmDateTime ) );  }  return false;}bool ctkDICOMDataset::SetElementAsInteger( const DcmTag& tag, long value, unsigned long pos ){  this->EnsureDcmDataSetIsInitialized();  //std::cerr << "TagVR: " << TagVR( tag ).toStdString() << std::endl;  return CheckCondition( putAndInsertSint32( tag, value, pos ) );}bool ctkDICOMDataset::SetElementAsSignedShort( const DcmTag& tag, int value, unsigned long pos ){  this->EnsureDcmDataSetIsInitialized();  //std::cerr << "TagVR: " << TagVR( tag ).toStdString() << std::endl;  return CheckCondition( putAndInsertSint16( tag, value, pos ) );}bool ctkDICOMDataset::SetElementAsUnsignedShort( const DcmTag& tag, int value, unsigned long pos ){  this->EnsureDcmDataSetIsInitialized();  //std::cerr << "TagVR: " << TagVR( tag ).toStdString() << std::endl;  return CheckCondition( putAndInsertUint16( tag, value, pos ) );}QString ctkDICOMDataset::TranslateDefinedTermPatientPosition( const QString& dt ){  static bool initialized = false;  static QMap<QString, QString> descriptionOfTerms;  if (!initialized)  {    descriptionOfTerms.insert("HFP",  "Head First - Prone");    descriptionOfTerms.insert("HFDR", "Head First - Decubitus Right");    descriptionOfTerms.insert("FFDR", "Feet First - Decubitus Right");    descriptionOfTerms.insert("FFP",  "Feet First - Prone");    descriptionOfTerms.insert("HFS",  "Head First - Supine");    descriptionOfTerms.insert("HFDL", "Head First - Decubitus Left");    descriptionOfTerms.insert("FFDL", "Feet First - Decubitus Left");    descriptionOfTerms.insert("FFS",  "Feet First - Supine");    initialized = true;  }  if ( descriptionOfTerms.contains( dt.toUpper() ) )  {    return descriptionOfTerms.value(dt.toUpper());  }  else  {    std::cerr << "Invalid enum for patient position" << std::endl;    return QString::null;  }}QString ctkDICOMDataset::TranslateDefinedTermModality( const QString& dt ){  static bool initialized = false;  static QMap<QString, QString> descriptionOfTerms;  if (!initialized)  {    descriptionOfTerms.insert("CR",  "Computed Radiography");    descriptionOfTerms.insert("CT",  "Computed Tomography");    descriptionOfTerms.insert("MR",  "Magnetic Resonance");    descriptionOfTerms.insert("NM",  "Nuclear Medicine");    descriptionOfTerms.insert("US",  "Ultrasound");    descriptionOfTerms.insert("OT",  "Other");    descriptionOfTerms.insert("BI",  "Biomagnetic imaging");    descriptionOfTerms.insert("CD",  "Color flow Doppler");    descriptionOfTerms.insert("DD",  "Duplex Doppler");    descriptionOfTerms.insert("ES",  "Endoscopy");    descriptionOfTerms.insert("LS",  "Laser surface scan");    descriptionOfTerms.insert("PT",  "Positron emission tomography (PET)");    descriptionOfTerms.insert("RG",  "Radiographic imaging (conventional film/screen)");    descriptionOfTerms.insert("ST",  "Single-photon emission computed tomograpy (SPECT)");    descriptionOfTerms.insert("TG",  "Thermography");    descriptionOfTerms.insert("XA",  "X-Ray Aniography");    descriptionOfTerms.insert("RF",  "Radio Fluoroscopy");    descriptionOfTerms.insert("RTIMAGE",  "Radiotherapy Image");    descriptionOfTerms.insert("RTDOSE",  "Radiotherapy Dose");    descriptionOfTerms.insert("RTSTRUCT",  "Radiotherapy Structure Set");    descriptionOfTerms.insert("RTPLAN",  "Radiotherapy Plan");    descriptionOfTerms.insert("RTRECORD",  "RT Treatment Record");    descriptionOfTerms.insert("HC",  "Hard Copy");    descriptionOfTerms.insert("DX",  "Digital Radiography");    descriptionOfTerms.insert("MG",  "Mammography");    descriptionOfTerms.insert("IO",  "Intra-oral Radiography");    descriptionOfTerms.insert("PX",  "Panoramic X-Ray");    descriptionOfTerms.insert("GM",  "General Microscopy");    descriptionOfTerms.insert("SM",  "Slide Microscopy");    descriptionOfTerms.insert("XC",  "External-camera Photography");    descriptionOfTerms.insert("PR",  "Presentation state");    descriptionOfTerms.insert("AU",  "Audio");    descriptionOfTerms.insert("ECG",  "Electrocardiography");    descriptionOfTerms.insert("EPS",  "Cardiac Electrophysiology");    descriptionOfTerms.insert("HD",  "Hemodynamic Waveform");    descriptionOfTerms.insert("SR",  "SR Document");    descriptionOfTerms.insert("IVUS",  "Intravascular Ultrasound");    descriptionOfTerms.insert("OP",  "Ophthalmic Photography");    descriptionOfTerms.insert("SMR",  "Stereometric Relationship");    descriptionOfTerms.insert("OCT",  "Optical Coherence Tomography (non-Ophthalmic)");    descriptionOfTerms.insert("OPR",  "Ophthalmic Refraction");    descriptionOfTerms.insert("OPV",  "Ophthalmic Visual Field");    descriptionOfTerms.insert("OPM",  "Ophthalmic Mapping");    descriptionOfTerms.insert("KO",  "Key Object Selection");    descriptionOfTerms.insert("SEG",  "Segmentation");    descriptionOfTerms.insert("REG",  "Registration");    descriptionOfTerms.insert("OPT",  "Ophthalmic Tomography");    descriptionOfTerms.insert("BDUS",  "Bone Densitometry (ultrasound)");    descriptionOfTerms.insert("BMD",  "Bone Densitometry (X-Ray)");    descriptionOfTerms.insert("DOC",  "Document");    // retired terms (but probably still in use)    descriptionOfTerms.insert("DS",  "Digital Subtraction Angiography");    descriptionOfTerms.insert("CF",  "Cinefluorography");    descriptionOfTerms.insert("DF",  "Digital fluoroscopy");    descriptionOfTerms.insert("VF",  "Videofluorography");    descriptionOfTerms.insert("AS",  "Angioscopy");    descriptionOfTerms.insert("CS",  "Cystoscopy");    descriptionOfTerms.insert("EC",  "Echocardiography");    descriptionOfTerms.insert("LP",  "Laparoscopy");    descriptionOfTerms.insert("FA",  "Fluorescein angiography ");    descriptionOfTerms.insert("CP",  "Culposcopy");    descriptionOfTerms.insert("DM",  "Digital microscopy");    descriptionOfTerms.insert("FS",  "Fundoscopy");    descriptionOfTerms.insert("MA",  "Magnetic resonance angiography");    descriptionOfTerms.insert("MS",  "Magnetic resonance spectroscopy");    initialized = true;  }  if ( descriptionOfTerms.contains( dt.toUpper() ) )  {    return descriptionOfTerms.value(dt.toUpper());  }  else  {    std::cerr << "Invalid enum for patient position" << std::endl;    return QString::null;  }}QString ctkDICOMDataset::TagKey( const DcmTag& tag ){  return QString("(%1,%2)").arg( tag.getGroup(), 4, 16, QLatin1Char('0')).arg( tag.getElement(), 4, 16, QLatin1Char('0') );}QString ctkDICOMDataset::TagDescription( const DcmTag& tag ){  if (!ctkDICOMDatasetPrivate::s_Dictionary->isDictionaryLoaded()) return QString("<no DICOM dictionary loaded. application broken>");  const DcmDictEntry* entry = ctkDICOMDatasetPrivate::s_Dictionary->findEntry(tag, NULL);  if (entry)  {    return QString(entry->getTagName());  }  else  {    return QString("<unknown>");  }}QString ctkDICOMDataset::TagVR( const DcmTag& tag ){  if (!ctkDICOMDatasetPrivate::s_Dictionary->isDictionaryLoaded()) return QString("<no DICOM dictionary loaded. application broken>");  const DcmDictEntry* entry = ctkDICOMDatasetPrivate::s_Dictionary->findEntry(tag, NULL);  if (entry)  {    return QString(entry->getVR().getVRName());  }  else  {    return QString("UN"); // unknown  }}QString ctkDICOMDataset::GetStoredSerialization(){  throw std::runtime_error("No serialization implemented for this object!");}void ctkDICOMDataset::SetStoredSerialization(QString serializedDataset){  throw std::runtime_error("No serialization implemented for this object!");}
 |