📄 gdcmdocument.cxx
字号:
/*=========================================================================
Program: gdcm
Module: $RCSfile: gdcmDocument.cxx,v $
Language: C++
Date: $Date: 2008-05-14 12:25:32 $
Version: $Revision: 1.29 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "gdcmDocument.h"
#include "gdcmValEntry.h"
#include "gdcmBinEntry.h"
#include "gdcmSeqEntry.h"
#include "gdcmGlobal.h"
#include "gdcmUtil.h"
#include "gdcmDebug.h"
#include "gdcmTS.h"
#include "gdcmDictSet.h"
#include "gdcmDocEntrySet.h"
#include "gdcmSQItem.h"
#include <vector>
#include <iomanip>
#include <fstream>
#include <ctype.h> // for isdigit
#include <stdlib.h> // for atoi
#if defined(__BORLANDC__)
#include <mem.h> // for memset
#endif
namespace gdcm
{
//-----------------------------------------------------------------------------
// Refer to Document::SetMaxSizeLoadEntry()
const unsigned int Document::MAX_SIZE_LOAD_ELEMENT_VALUE = 0xfff; // 4096
//-----------------------------------------------------------------------------
// Constructor / Destructor
// Constructors and destructors are protected to avoid user to invoke directly
/**
* \brief This default constructor neither loads nor parses the file.
* You should then invoke \ref Document::Load.
*
*/
Document::Document()
:ElementSet(-1)
{
Fp = 0;
SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
Initialize();
SwapCode = 1234;
Filetype = ExplicitVR;
// Load will set it to true if sucessfull
Group0002Parsed = false;
IsDocumentAlreadyLoaded = false;
IsDocumentModified = true;
LoadMode = LD_ALL; // default : load everything, later
SetFileName("");
}
#ifndef GDCM_LEGACY_REMOVE
/**
* \brief Constructor (DEPRECATED : not to break the API)
* @param fileName 'Document' (File or DicomDir) to be open for parsing
*/
Document::Document( std::string const &fileName )
:ElementSet(-1)
{
Fp = 0;
SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
Initialize();
SwapCode = 1234;
Filetype = ExplicitVR;
Group0002Parsed = false;
LoadMode = LD_ALL; // Load everything, later
// Load will set it to true if sucessfull
IsDocumentAlreadyLoaded = false;
IsDocumentModified = true;
SetFileName(fileName);
Load( );
}
#endif
/**
* \brief Canonical destructor.
*/
Document::~Document ()
{
CloseFile();
}
//-----------------------------------------------------------------------------
// Public
/**
* \brief Loader. use SetLoadMode(), SetFileName() before !
* @return false if file cannot be open or no swap info was found,
* or no tag was found.
*/
bool Document::Load( )
{
if ( GetFileName() == "" )
{
gdcmWarningMacro( "Use SetFileName, before !" );
return false;
}
return DoTheLoadingDocumentJob( );
}
#ifndef GDCM_LEGACY_REMOVE
/**
* \brief Loader. (DEPRECATED : not to break the API)
* @param fileName 'Document' (File or DicomDir) to be open for parsing
* @return false if file cannot be open or no swap info was found,
* or no tag was found.
*/
bool Document::Load( std::string const &fileName )
{
Filename = fileName;
return DoTheLoadingDocumentJob( );
}
#endif
/**
* \brief Performs the Loading Job (internal use only)
* @return false if file cannot be open or no swap info was found,
* or no tag was found.
*/
bool Document::DoTheLoadingDocumentJob( )
{
if ( ! IsDocumentModified ) // Nothing to do !
return true;
ClearEntry();
Fp = 0;
if ( !OpenFile() )
{
// warning already performed in OpenFile()
Filetype = Unknown;
return false;
}
Group0002Parsed = false;
gdcmDebugMacro( "Starting parsing of file: " << Filename.c_str());
// Computes the total length of the file
Fp->seekg(0, std::ios::end); // Once per Document !
long lgt = Fp->tellg(); // Once per Document !
Fp->seekg(0, std::ios::beg); // Once per Document !
// CheckSwap returns a boolean
// (false if no swap info of any kind was found)
if (! CheckSwap() )
{
gdcmWarningMacro( "Neither a DICOM V3 nor an ACR-NEMA file: "
<< Filename.c_str());
CloseFile();
return false;
}
long beg = Fp->tellg(); // just after DICOM preamble (if any)
lgt -= beg; // remaining length to parse
// Recursive call.
// Loading is done during parsing
ParseDES( this, beg, lgt, false); // delim_mode is first defaulted to false
if ( IsEmpty() )
{
gdcmErrorMacro( "No tag in internal hash table for: "
<< Filename.c_str());
CloseFile();
return false;
}
IsDocumentAlreadyLoaded = true;
//Fp->seekg(0, std::ios::beg); // Once per Document!
// Load 'non string' values
std::string PhotometricInterpretation = GetEntryValue(0x0028,0x0004);
if ( PhotometricInterpretation == "PALETTE COLOR " )
{
// FIXME
// Probabely this line should be outside the 'if'
// Try to find an image sample holding a 'gray LUT'
LoadEntryBinArea(0x0028,0x1200); // gray LUT
/// FIXME
/// The tags refered by the three following lines used to be CORRECTLY
/// defined as having an US Value Representation in the public
/// dictionary. BUT the semantics implied by the three following
/// lines state that the corresponding tag contents are in fact
/// the ones of a BinEntry.
/// In order to fix things "Quick and Dirty" the dictionary was
/// altered on PURPOSE but now contains a WRONG value.
/// In order to fix things and restore the dictionary to its
/// correct value, one needs to decide of the semantics by deciding
/// whether the following tags are either :
/// - multivaluated US, and hence loaded as ValEntry, but afterwards
/// also used as BinEntry, which requires the proper conversion,
/// - OW, and hence loaded as BinEntry, but afterwards also used
/// as ValEntry, which requires the proper conversion.
// --> OB (byte aray) or OW (short int aray)
// The actual VR has to be deduced from other entries.
// Our way of loading them may fail in some cases :
// We must or not SwapByte depending on other field values.
LoadEntryBinArea(0x0028,0x1201); // R LUT
LoadEntryBinArea(0x0028,0x1202); // G LUT
LoadEntryBinArea(0x0028,0x1203); // B LUT
// Segmented Red Palette Color LUT Data
LoadEntryBinArea(0x0028,0x1221);
// Segmented Green Palette Color LUT Data
LoadEntryBinArea(0x0028,0x1222);
// Segmented Blue Palette Color LUT Data
LoadEntryBinArea(0x0028,0x1223);
}
//FIXME later : how to use it?
SeqEntry *modLutSeq = GetSeqEntry(0x0028,0x3000); // Modality LUT Sequence
if ( modLutSeq !=0 )
{
SQItem *sqi= modLutSeq->GetFirstSQItem();
if ( sqi != 0 )
{
BinEntry *b = sqi->GetBinEntry(0x0028,0x3006);
if ( b != 0 )
{
if ( b->GetLength() != 0 )
{
// FIXME : CTX dependent means : contexted dependant.
// see upper comment.
LoadEntryBinArea(b); //LUT Data (CTX dependent)
}
}
}
}
// Force Loading some more elements if user asked to.
gdcm::DocEntry *d;
for (ListElements::iterator it = UserForceLoadList.begin();
it != UserForceLoadList.end();
++it)
{
gdcmDebugMacro( "Force Load " << std::hex
<< (*it).Group << "|" <<(*it).Elem );
d = GetDocEntry( (*it).Group, (*it).Elem);
if ( d == NULL)
{
gdcmWarningMacro( "You asked to ForceLoad " << std::hex
<< (*it).Group <<"|"<< (*it).Elem
<< " that doesn't exist" );
continue;
}
if ( dynamic_cast<ValEntry *>(d) )
{
LoadDocEntry(d, true);
continue;
}
BinEntry *b = dynamic_cast<BinEntry *>(d);
if ( b )
{
LoadEntryBinArea(b);
b->SetValue(GDCM_BINLOADED);
continue;
}
if ( dynamic_cast<SeqEntry *>(d) )
{
gdcmWarningMacro( "You cannot 'ForceLoad' a SeqEntry :" << std::hex
<< (*it).Group <<"|"<< (*it).Elem );
continue;
}
}
CloseFile();
// ----------------------------
// Specific code to allow gdcm to read ACR-LibIDO formated images
// Note: ACR-LibIDO is an extension of the ACR standard that was
// used at CREATIS. For the time being (say a couple of years)
// we keep this kludge to allow CREATIS users
// reading their old images.
//
// if recognition code tells us we deal with a LibIDO image
// we switch lineNumber and columnNumber
//
std::string RecCode;
RecCode = GetEntryValue(0x0008, 0x0010); // recognition code (RET)
if (RecCode == "ACRNEMA_LIBIDO_1.1" ||
RecCode == "ACRNEMA_LIBIDO_1.0" ||
RecCode == "CANRME_AILIBOD1_0." ||
RecCode == "CANRME_AILIBOD1_1." ) // for brain-damaged softwares
// with "little-endian strings"
{
Filetype = ACR_LIBIDO;
std::string rows = GetEntryValue(0x0028, 0x0010);
std::string columns = GetEntryValue(0x0028, 0x0011);
SetValEntry(columns, 0x0028, 0x0010);
SetValEntry(rows , 0x0028, 0x0011);
}
// --- End of ACR-LibIDO kludge ---
return true;
}
/**
* \brief Adds a new element we want to load anyway
* @param group Group number of the target tag.
* @param elem Element number of the target tag.
*/
void Document::AddForceLoadElement (uint16_t group, uint16_t elem)
{
Element el;
el.Group = group;
el.Elem = elem;
UserForceLoadList.push_back(el);
}
/**
* \brief Get the public dictionary used
*/
Dict *Document::GetPubDict()
{
return RefPubDict;
}
/**
* \brief Get the shadow dictionary used
*/
Dict *Document::GetShaDict()
{
return RefShaDict;
}
/**
* \brief Set the shadow dictionary used
* @param dict dictionary to use in shadow
*/
bool Document::SetShaDict(Dict *dict)
{
RefShaDict = dict;
return !RefShaDict;
}
/**
* \brief Set the shadow dictionary used
* @param dictName name of the dictionary to use in shadow
*/
bool Document::SetShaDict(DictKey const &dictName)
{
RefShaDict = Global::GetDicts()->GetDict(dictName);
return !RefShaDict;
}
/**
* \brief This predicate tells us whether or not the current Document
* was properly parsed and contains at least *one* Dicom Element
* (and nothing more, sorry).
* @return false when we're 150 % sure it's NOT a Dicom/Acr file,
* true otherwise.
*/
bool Document::IsParsable()
{
if ( Filetype == Unknown )
{
gdcmWarningMacro( "Wrong filetype for " << GetFileName());
return false;
}
if ( IsEmpty() )
{
gdcmWarningMacro( "No tag in internal hash table.");
return false;
}
return true;
}
/**
* \brief This predicate tells us whether or not the current Document
* was properly parsed and contains at least *one* Dicom Element
* (and nothing more, sorry).
* @return false when we're 150 % sure it's NOT a Dicom/Acr file,
* true otherwise.
*/
bool Document::IsReadable()
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -