123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998 |
- /*=============================================================================
- Library: CTK
- Copyright (c) German Cancer Research Center,
- Division of Medical and Biological Informatics
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- =============================================================================*/
- #include "ctkDICOMItem.h"
- #include <dcmtk/dcmdata/dctk.h>
- #include <dcmtk/dcmdata/dcostrmb.h>
- #include <dcmtk/dcmdata/dcistrmb.h>
- #include <stdexcept>
- class ctkDICOMItemPrivate
- {
- public:
- ctkDICOMItemPrivate() : m_DcmItem(0), m_TakeOwnership(true) {}
- QString m_SpecificCharacterSet;
- bool m_DICOMDataSetInitialized;
- bool m_StrictErrorHandling;
- DcmItem* m_DcmItem;
- bool m_TakeOwnership;
- };
- ctkDICOMItem::ctkDICOMItem(bool strictErrorHandling)
- :d_ptr(new ctkDICOMItemPrivate)
- {
- Q_D(ctkDICOMItem);
- d->m_DcmItem = new DcmDataset();
- d->m_TakeOwnership = true;
- d->m_DICOMDataSetInitialized = false;
- d->m_StrictErrorHandling = strictErrorHandling;
- }
- ctkDICOMItem::~ctkDICOMItem()
- {
- Q_D(ctkDICOMItem);
- if ( d->m_TakeOwnership)
- {
- delete d->m_DcmItem;
- }
- }
- void ctkDICOMItem::InitializeFromItem(DcmItem *dataset, bool takeOwnership)
- {
- Q_D(ctkDICOMItem);
- if(d->m_DcmItem != dataset)
- {
- if (d->m_TakeOwnership)
- {
- delete d->m_DcmItem;
- }
- d->m_DcmItem = NULL;
- }
- if (dataset)
- {
- d->m_DcmItem=dataset;
- d->m_TakeOwnership = takeOwnership;
- if (!d->m_DICOMDataSetInitialized)
- {
- d->m_DICOMDataSetInitialized = true;
- OFString encoding;
- if ( CheckCondition( dataset->findAndGetOFString(DCM_SpecificCharacterSet, encoding) ) )
- {
- d->m_SpecificCharacterSet = encoding.c_str();
- }
- }
- 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 ctkDICOMItem::InitializeFromFile(const QString& filename,
- const E_TransferSyntax readXfer,
- const E_GrpLenEncoding groupLength,
- const Uint32 maxReadLength,
- const E_FileReadMode readMode)
- {
- DcmDataset *dataset;
- DcmFileFormat fileformat;
- OFCondition status = fileformat.loadFile(filename.toLatin1().data(), readXfer, groupLength, maxReadLength, readMode);
- dataset = fileformat.getAndRemoveDataset();
- if (!status.good())
- {
- qDebug() << "Could not load " << filename << "\nDCMTK says: " << status.text();
- delete dataset;
- return;
- }
- InitializeFromItem(dataset, true);
- }
- void ctkDICOMItem::Serialize()
- {
- Q_D(ctkDICOMItem);
- EnsureDcmDataSetIsInitialized();
- // store content of current DcmDataset (our parent) as QByteArray into m_ctkDICOMItem
- Uint32 buffersize = 1024*1024; // reserve 1MB
- char* writebuffer = new char[buffersize];
- // write into buffer
- DcmOutputBufferStream dcmbuffer(writebuffer, buffersize);
- d->m_DcmItem->transferInit();
- OFCondition condition = d->m_DcmItem->write(dcmbuffer, EXS_LittleEndianImplicit, EET_UndefinedLength, NULL );
- d->m_DcmItem->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 << " ctkDICOMItem: 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::fromLatin1(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 ctkDICOMItem::MarkForInitialization()
- {
- Q_D(ctkDICOMItem);
- d->m_DICOMDataSetInitialized = false;
- }
- bool ctkDICOMItem::IsInitialized() const
- {
- Q_D(const ctkDICOMItem);
- return d->m_DICOMDataSetInitialized;
- }
- void ctkDICOMItem::EnsureDcmDataSetIsInitialized() const
- {
- if ( ! this->IsInitialized() )
- {
- throw std::logic_error("Calling methods on uninitialized ctkDICOMItem");
- }
- // const_cast<ctkDICOMItem*>(this)->Deserialize();
- }
- void ctkDICOMItem::Deserialize()
- {
- Q_D(ctkDICOMItem);
- // read attribute m_ctkDICOMItem
- // 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 << " ctkDICOMItem: Deserialize Dataset from string of size " << stringbuffer.size() << "\n" << stringbuffer.toStdString() << std::endl;
- QByteArray qtArray = QByteArray::fromBase64( stringbuffer.toLatin1() );
- //std::cerr << "** " << (void*)this << " ctkDICOMItem: 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->InitializeFromItem(&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: "
- << static_cast<int>(dataset.transferState()) << std::endl;
- std::cerr << "Could not DcmDataset::read(..): "
- << condition.text() << std::endl;
- //throw std::invalid_argument( std::string("Could not DcmDataset::read(..): ") + condition.text() );
- }
- }
- DcmItem& ctkDICOMItem::GetDcmItem() const
- {
- const Q_D(ctkDICOMItem);
- return *d->m_DcmItem;
- }
- OFCondition ctkDICOMItem::findAndGetElement(const DcmTag& tag, DcmElement*& element, const OFBool searchIntoSub) const
- {
- EnsureDcmDataSetIsInitialized();
- // this one const_cast allows us to declare quite a lot of methods nicely with const
- return GetDcmItem().findAndGetElement(tag, element, searchIntoSub);
- }
- OFCondition ctkDICOMItem::findAndGetOFString(const DcmTag& tag, OFString& value, const unsigned long pos, const OFBool searchIntoSub) const
- {
- EnsureDcmDataSetIsInitialized();
- // this second const_cast allows us to declare quite a lot of methods nicely with const
- return GetDcmItem().findAndGetOFString(tag, value, pos, searchIntoSub);
- }
- bool ctkDICOMItem::CheckCondition(const OFCondition& condition)
- {
- if ( condition.bad() )
- {
- //std::cerr << "Bad return code (" << condition.code() << "): " << condition.text() << std::endl;
- }
- return condition.good();
- }
- bool ctkDICOMItem::CopyElement( DcmDataset* dataset, const DcmTagKey& tag, int type )
- {
- Q_D(ctkDICOMItem);
- 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;
- if (dataset == d->m_DcmItem)
- {
- throw std::logic_error("Trying to copy tag to yourself. Please check application logic!");
- }
- // 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( d->m_DcmItem->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 ctkDICOMItem::Decode( const DcmTag& tag, const OFString& raw ) const
- {
- Q_D(const ctkDICOMItem);
- // 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 6", "UTF-8"); // actually ASCII, but ok
- 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_IR 192", "UTF-8");
- // japanese
- qtEncodingNamesForDICOMEncodingNames.insert("ISO 2022 IR 13", "ISO 2022-JP"); // Single byte charset, JIS X 0201: Katakana, Romaji
- qtEncodingNamesForDICOMEncodingNames.insert("ISO 2022 IR 87", "ISO 2022-JP"); // Multi byte charset, JIS X 0208: Kanji, Kanji set
- qtEncodingNamesForDICOMEncodingNames.insert("ISO 2022 IR 159", "ISO 2022-JP");
- // korean
- qtEncodingNamesForDICOMEncodingNames.insert("ISO 2022 IR 149", "EUC-KR"); // Multi byte charset, KS X 1001: Hangul, Hanja
- // 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.toLatin1() );
- if (!codec)
- {
- std::cerr << "Could not create QTextCodec object for '" << encodingName.toStdString() << "'. Using default encoding instead." << std::endl;
- decoders.insert( encodingName, QTextCodec::codecForName("UTF-8")->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 ctkDICOMItem::Encode( const DcmTag& tag, const QString& qstring ) const
- {
- // TODO: respect given character-set when encoding; see Decode()
- Q_UNUSED(tag);
- return OFString( qstring.toLatin1().data() ); // Latin1 is ISO 8859, which is the default character set of DICOM (PS 3.5-2008, Page 18)
- }
- QString ctkDICOMItem::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<ctkDICOMItem*>(this)->findAndGetOFString(tag, s, i) ) )
- {
- qsl << Decode( tag, s );
- }
- }
- return qsl.join("\\");
- }
- QString ctkDICOMItem::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 ctkDICOMItem::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 ctkDICOMItem::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 ctkDICOMItem::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 ctkDICOMItem::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 ctkDICOMItem::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 ctkDICOMItem::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 ctkDICOMItem::GetElementAsDouble( const DcmTag& tag, unsigned long pos ) const
- {
- Q_D(const ctkDICOMItem);
- this->EnsureDcmDataSetIsInitialized();
- DcmElement* element(NULL);
- findAndGetElement(tag, element);
- DcmDecimalString* ds = dynamic_cast<DcmDecimalString*>(element);
- if (!ds)
- {
- if (d->m_StrictErrorHandling)
- {
- throw std::logic_error("Element not found or not a decimal number");
- }
- else
- {
- return 0.0;
- }
- }
- Float64 dvalue;
- ds->getFloat64(dvalue, pos);
- return dvalue;
- }
- long ctkDICOMItem::GetElementAsInteger( const DcmTag& tag, unsigned long pos ) const
- {
- Q_D(const ctkDICOMItem);
- this->EnsureDcmDataSetIsInitialized();
- DcmElement* element(NULL);
- findAndGetElement(tag, element);
- DcmIntegerString* is = dynamic_cast<DcmIntegerString*>(element);
- if (!is)
- {
- if (d->m_StrictErrorHandling)
- {
- throw std::logic_error("Element not found or not an integer");
- }
- else
- {
- return 0;
- }
- }
- Sint32 i = 0;
- is->getSint32(i, pos);
- return i;
- }
- int ctkDICOMItem::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 ctkDICOMItem::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 ctkDICOMItem::SetElementAsString( const DcmTag& tag, QString string )
- {
- Q_D(ctkDICOMItem);
- this->EnsureDcmDataSetIsInitialized();
- // TODO: Evaluate DICOM tag for proper encoding (see GetElementAsString())
- return CheckCondition( d->m_DcmItem->putAndInsertString( tag, string.toLatin1().data() ) );
- }
- bool ctkDICOMItem::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 ctkDICOMItem::SetElementAsPersonName( const DcmTag& tag, ctkDICOMPersonName personName )
- {
- Q_D(ctkDICOMItem);
- 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( d->m_DcmItem->insert( dcmPersonName ) );
- }
- return false;
- }
- bool ctkDICOMItem::SetElementAsPersonNameList( const DcmTag& tag, ctkDICOMPersonNameList personNameList )
- {
- Q_UNUSED(tag);
- Q_UNUSED(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 ctkDICOMItem::SetElementAsDate( const DcmTag& tag, QDate date )
- {
- Q_D(ctkDICOMItem);
- this->EnsureDcmDataSetIsInitialized();
- OFDate ofDate( date.year(), date.month(), date.day() );
- DcmDate* dcmDate = new DcmDate( tag ); // TODO leak?
- if ( CheckCondition( dcmDate->setOFDate( ofDate ) ) )
- {
- return CheckCondition( d->m_DcmItem->insert( dcmDate ) );
- }
- return false;
- }
- bool ctkDICOMItem::SetElementAsTime( const DcmTag& tag, QTime time )
- {
- Q_D(ctkDICOMItem);
- this->EnsureDcmDataSetIsInitialized();
- OFTime ofTime( time.hour(), time.minute(), time.second() );
- DcmTime* dcmTime = new DcmTime( tag ); // TODO leak?
- if ( CheckCondition( dcmTime->setOFTime( ofTime ) ) )
- {
- return CheckCondition( d->m_DcmItem->insert( dcmTime ) );
- }
- return false;
- }
- bool ctkDICOMItem::SetElementAsDateTime( const DcmTag& tag, QDateTime dateTime )
- {
- Q_D(ctkDICOMItem);
- 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( d->m_DcmItem->insert( dcmDateTime ) );
- }
- return false;
- }
- bool ctkDICOMItem::SetElementAsInteger( const DcmTag& tag, long value, unsigned long pos )
- {
- Q_D(ctkDICOMItem);
- this->EnsureDcmDataSetIsInitialized();
- //std::cerr << "TagVR: " << TagVR( tag ).toStdString() << std::endl;
- return CheckCondition( d->m_DcmItem->putAndInsertSint32( tag, value, pos ) );
- }
- bool ctkDICOMItem::SetElementAsSignedShort( const DcmTag& tag, int value, unsigned long pos )
- {
- Q_D(ctkDICOMItem);
- this->EnsureDcmDataSetIsInitialized();
- //std::cerr << "TagVR: " << TagVR( tag ).toStdString() << std::endl;
- return CheckCondition( d->m_DcmItem->putAndInsertSint16( tag, value, pos ) );
- }
- bool ctkDICOMItem::SetElementAsUnsignedShort( const DcmTag& tag, int value, unsigned long pos )
- {
- Q_D(ctkDICOMItem);
- this->EnsureDcmDataSetIsInitialized();
- //std::cerr << "TagVR: " << TagVR( tag ).toStdString() << std::endl;
- return CheckCondition( d->m_DcmItem->putAndInsertUint16( tag, value, pos ) );
- }
- QString ctkDICOMItem::GetStudyInstanceUID() const
- {
- return this->GetElementAsString(DCM_StudyInstanceUID);
- }
- QString ctkDICOMItem::GetSeriesInstanceUID() const
- {
- return this->GetElementAsString(DCM_SeriesInstanceUID);
- }
- QString ctkDICOMItem::GetSOPInstanceUID() const
- {
- return this->GetElementAsString(DCM_SOPInstanceUID);
- }
- QString ctkDICOMItem::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 ctkDICOMItem::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 ctkDICOMItem::TagKey( const DcmTag& tag )
- {
- return QString("(%1,%2)").arg( tag.getGroup(), 4, 16, QLatin1Char('0')).arg( tag.getElement(), 4, 16, QLatin1Char('0') );
- }
- QString ctkDICOMItem::TagDescription( const DcmTag& tag )
- {
- if (!dcmDataDict.isDictionaryLoaded())
- return QString("<no DICOM dictionary loaded. application broken>");
- const DcmDataDictionary& globalDict = dcmDataDict.rdlock();
- const DcmDictEntry* entry = globalDict.findEntry(tag, NULL);
- QString returnName("Unknown");
- if (entry)
- {
- returnName = entry->getTagName();
- }
- dcmDataDict.unlock();
- return returnName;
- }
- QString ctkDICOMItem::TagVR( const DcmTag& tag )
- {
- if (!dcmDataDict.isDictionaryLoaded()) return QString("<no DICOM dictionary loaded. application broken>");
- const DcmDataDictionary& globalDataDict = dcmDataDict.rdlock();
- const DcmDictEntry* entry = globalDataDict.findEntry(tag, NULL);
- QString returnVR("UN");
- if (entry)
- {
- returnVR = entry->getVR().getVRName();
- }
- dcmDataDict.unlock();
- return returnVR;
- }
- QString ctkDICOMItem::GetStoredSerialization()
- {
- throw std::runtime_error("No serialization implemented for this object!");
- }
- void ctkDICOMItem::SetStoredSerialization(QString serializedDataset)
- {
- Q_UNUSED(serializedDataset);
- throw std::runtime_error("No serialization implemented for this object!");
- }
- bool ctkDICOMItem::SaveToFile(const QString& filePath) const
- {
- Q_D(const ctkDICOMItem);
- if (! dynamic_cast<DcmDataset*>(d->m_DcmItem) )
- {
- return false;
- }
- DcmFileFormat* fileformat = new DcmFileFormat ( dynamic_cast<DcmDataset*>(d->m_DcmItem) );
- OFCondition status = fileformat->saveFile ( qPrintable(QDir::toNativeSeparators( filePath)) );
- delete fileformat;
- return status.good();
- }
|