-// gdcmHeader.cxx
+// $Header: /cvs/public/gdcm/src/Attic/gdcmHeader.cxx,v 1.66 2003/05/21 14:42:46 frog Exp $
#include <stdio.h>
#include <cerrno>
#include <sstream>
#include "gdcmUtil.h"
#include "gdcmHeader.h"
-
-#include <iddcmjpeg.h>
+using namespace std;
// Refer to gdcmHeader::CheckSwap()
#define HEADER_LENGTH_TO_READ 256
// Refer to gdcmHeader::SetMaxSizeLoadElementValue()
#define _MaxSizeLoadElementValue_ 1024
-VRHT * gdcmHeader::dicom_vr = (VRHT*)0;
-
void gdcmHeader::Initialise(void) {
- if (!gdcmHeader::dicom_vr)
- InitVRDict();
- Dicts = new gdcmDictSet();
+ dicom_vr = gdcmGlobal::GetVR();
+ Dicts = gdcmGlobal::GetDicts();
RefPubDict = Dicts->GetDefaultPubDict();
RefShaDict = (gdcmDict*)0;
}
-gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error)
- throw(gdcmFileError) {
+gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error) {
SetMaxSizeLoadElementValue(_MaxSizeLoadElementValue_);
filename = InFilename;
Initialise();
- fp=fopen(InFilename,"rb");
+ if ( !OpenFile(exception_on_error))
+ return;
+ ParseHeader();
+ LoadElements();
+ CloseFile();
+}
+
+bool gdcmHeader::OpenFile(bool exception_on_error)
+ throw(gdcmFileError) {
+ fp=fopen(filename.c_str(),"rb");
if(exception_on_error) {
if(!fp)
throw gdcmFileError("gdcmHeader::gdcmHeader(const char *, bool)");
}
- else
- dbg.Error(!fp, "gdcmHeader::gdcmHeader cannot open file", InFilename);
- ParseHeader();
- AddAndDefaultElements();
+ if ( fp )
+ return true;
+ dbg.Verbose(0, "gdcmHeader::gdcmHeader cannot open file", filename.c_str());
+ return false;
}
+bool gdcmHeader::CloseFile(void) {
+ int closed = fclose(fp);
+ fp = (FILE *)0;
+ if (! closed)
+ return false;
+ return true;
+}
gdcmHeader::~gdcmHeader (void) {
- //FIXME obviously there is much to be done here !
- fclose(fp);
+ dicom_vr = (gdcmVR*)0;
+ Dicts = (gdcmDictSet*)0;
+ RefPubDict = (gdcmDict*)0;
+ RefShaDict = (gdcmDict*)0;
return;
}
-void gdcmHeader::InitVRDict (void) {
- if (dicom_vr) {
- dbg.Verbose(0, "gdcmHeader::InitVRDict:", "VR dictionary allready set");
- return;
- }
- VRHT *vr = new VRHT;
- (*vr)["AE"] = "Application Entity"; // At most 16 bytes
- (*vr)["AS"] = "Age String"; // Exactly 4 bytes
- (*vr)["AT"] = "Attribute Tag"; // 2 16-bit unsigned short integers
- (*vr)["CS"] = "Code String"; // At most 16 bytes
- (*vr)["DA"] = "Date"; // Exactly 8 bytes
- (*vr)["DS"] = "Decimal String"; // At most 16 bytes
- (*vr)["DT"] = "Date Time"; // At most 26 bytes
- (*vr)["FL"] = "Floating Point Single"; // 32-bit IEEE 754:1985 float
- (*vr)["FD"] = "Floating Point Double"; // 64-bit IEEE 754:1985 double
- (*vr)["IS"] = "Integer String"; // At most 12 bytes
- (*vr)["LO"] = "Long String"; // At most 64 chars
- (*vr)["LT"] = "Long Text"; // At most 10240 chars
- (*vr)["OB"] = "Other Byte String"; // String of bytes (vr independant)
- (*vr)["OW"] = "Other Word String"; // String of 16-bit words (vr dep)
- (*vr)["PN"] = "Person Name"; // At most 64 chars
- (*vr)["SH"] = "Short String"; // At most 16 chars
- (*vr)["SL"] = "Signed Long"; // Exactly 4 bytes
- (*vr)["SQ"] = "Sequence of Items"; // Not Applicable
- (*vr)["SS"] = "Signed Short"; // Exactly 2 bytes
- (*vr)["ST"] = "Short Text"; // At most 1024 chars
- (*vr)["TM"] = "Time"; // At most 16 bytes
- (*vr)["UI"] = "Unique Identifier"; // At most 64 bytes
- (*vr)["UL"] = "Unsigned Long "; // Exactly 4 bytes
- (*vr)["UN"] = "Unknown"; // Any length of bytes
- (*vr)["US"] = "Unsigned Short "; // Exactly 2 bytes
- (*vr)["UT"] = "Unlimited Text"; // At most 2^32 -1 chars
- dicom_vr = vr;
-}
+// Fourth semantics:
+// CMD Command
+// META Meta Information
+// DIR Directory
+// ID
+// PAT Patient
+// ACQ Acquisition
+// REL Related
+// IMG Image
+// SDY Study
+// VIS Visit
+// WAV Waveform
+// PRC
+// DEV Device
+// NMI Nuclear Medicine
+// MED
+// BFS Basic Film Session
+// BFB Basic Film Box
+// BIB Basic Image Box
+// BAB
+// IOB
+// PJ
+// PRINTER
+// RT Radio Therapy
+// DVH
+// SSET
+// RES Results
+// CRV Curve
+// OLY Overlays
+// PXL Pixels
+//
/**
* \ingroup gdcmHeader
entCur = deb + 128;
if(memcmp(entCur, "DICM", (size_t)4) == 0) {
- filetype = TrueDicom;
dbg.Verbose(1, "gdcmHeader::CheckSwap:", "looks like DICOM Version3");
- } else {
- filetype = Unknown;
- dbg.Verbose(1, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file");
- }
-
- if(filetype == TrueDicom) {
// Next, determine the value representation (VR). Let's skip to the
// first element (0002, 0000) and check there if we find "UL"
// - or "OB" if the 1st one is (0002,0001) -,
// * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
// i.e. a total of 136 bytes.
entCur = deb + 136;
+ // FIXME
+ // Use gdcmHeader::dicom_vr to test all the possibilities
+ // instead of just checking for UL, OB and UI !?
if( (memcmp(entCur, "UL", (size_t)2) == 0) ||
- (memcmp(entCur, "OB", (size_t)2) == 0) )
+ (memcmp(entCur, "OB", (size_t)2) == 0) ||
+ (memcmp(entCur, "UI", (size_t)2) == 0) )
{
filetype = ExplicitVR;
dbg.Verbose(1, "gdcmHeader::CheckSwap:",
rewind(fp);
fseek (fp, 132L, SEEK_SET);
return;
- } // End of TrueDicom
+ } // End of DicomV3
// Alas, this is not a DicomV3 file and whatever happens there is no file
// preamble. We can reset the file position indicator to where the data
// is (i.e. the beginning of the file).
+ dbg.Verbose(1, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file");
rewind(fp);
// Our next best chance would be to be considering a 'clean' ACR/NEMA file.
// It is time for despaired wild guesses. So, let's assume this file
// happens to be 'dirty' ACR/NEMA, i.e. the length of the group is
// not present. Then the only info we have is the net2host one.
+ filetype = Unknown;
if (! net2host )
sw = 0;
else
sw = 3412;
}
-void gdcmHeader::GetPixels(size_t lgrTotale, void* _Pixels) {
- size_t pixelsOffset;
- pixelsOffset = GetPixelOffset();
- fseek(fp, pixelsOffset, SEEK_SET);
- if (IsJPEGLossless()) {
- _Pixels=_IdDcmJpegRead(fp);
- } else {
- fread(_Pixels, 1, lgrTotale, fp);
- }
-}
-
-
-
/**
* \ingroup gdcmHeader
* \brief Find the value representation of the current tag.
*/
-void gdcmHeader::FindVR( ElValue *ElVal) {
+void gdcmHeader::FindVR( gdcmElValue *ElVal) {
if (filetype != ExplicitVR)
return;
// CLEANME searching the dicom_vr at each occurence is expensive.
// PostPone this test in an optional integrity check at the end
// of parsing or only in debug mode.
- if ( RealExplicit && !dicom_vr->count(vr) )
+ if ( RealExplicit && !dicom_vr->Count(vr) )
RealExplicit= false;
if ( RealExplicit ) {
* @return True when ImplicitVRLittleEndian found. False in all other cases.
*/
bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
* @return True when ExplicitVRLittleEndian found. False in all other cases.
*/
bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
* @return True when DeflatedExplicitVRLittleEndian found. False in all other cases.
*/
bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
* @return True when big endian found. False in all other cases.
*/
bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
* @return True when JPEGBaseLineProcess1found. False in all other cases.
*/
bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
// faire qq chose d'intelligent a la place de ça
bool gdcmHeader::IsJPEGLossless(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
const char * Transfert = Element->GetValue().c_str();
+ printf("TransfertSyntx %s\n",Transfert);
if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true;
if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true;
return false;
* @return True when JPEGExtendedProcess2-4 found. False in all other cases.
*/
bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
* @return True when JPEGExtendedProcess3-5 found. False in all other cases.
*/
bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
* other cases.
*/
bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) {
- ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+ gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
return true;
return false;
}
+/**
+ * \ingroup gdcmHeader
+ * \brief Predicate for dicom version 3 file.
+ * @return True when the file is a dicom version 3.
+ */
+bool gdcmHeader::IsDicomV3(void) {
+ if ( (filetype == ExplicitVR)
+ || (filetype == ImplicitVR) )
+ return true;
+ return false;
+}
/**
* \ingroup gdcmHeader
* the parser went Jabberwocky) one can hope improving things by
* applying this heuristic.
*/
-void gdcmHeader::FixFoundLength(ElValue * ElVal, guint32 FoundLength) {
+void gdcmHeader::FixFoundLength(gdcmElValue * ElVal, guint32 FoundLength) {
if ( FoundLength == 0xffffffff)
FoundLength = 0;
ElVal->SetLength(FoundLength);
return TotalLength;
}
-void gdcmHeader::FindLength(ElValue * ElVal) {
+void gdcmHeader::FindLength(gdcmElValue * ElVal) {
guint16 element = ElVal->GetElement();
string vr = ElVal->GetVR();
guint16 length16;
// and the dictionary entry depending on them.
guint16 CorrectGroup = SwapShort(ElVal->GetGroup());
guint16 CorrectElem = SwapShort(ElVal->GetElement());
- gdcmDictEntry * NewTag = GetDictEntryByKey(CorrectGroup, CorrectElem);
+ gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup,
+ CorrectElem);
if (!NewTag) {
// This correct tag is not in the dictionary. Create a new one.
NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem);
* @return The suggested integer.
*/
guint32 gdcmHeader::SwapLong(guint32 a) {
- // FIXME: il pourrait y avoir un pb pour les entiers negatifs ...
switch (sw) {
case 0 :
break;
(void)fseek(fp, (long)NBytes, SEEK_CUR);
}
-void gdcmHeader::SkipElementValue(ElValue * ElVal) {
+void gdcmHeader::SkipElementValue(gdcmElValue * ElVal) {
SkipBytes(ElVal->GetLength());
}
* than the value specified with
* gdcmHeader::SetMaxSizeLoadElementValue()
*/
-void gdcmHeader::LoadElementValue(ElValue * ElVal) {
+void gdcmHeader::LoadElementValue(gdcmElValue * ElVal) {
size_t item_read;
guint16 group = ElVal->GetGroup();
guint16 elem = ElVal->GetElement();
fseek(fp, (long)ElVal->GetOffset(), SEEK_SET);
- // Sequences not treated yet !
+ // FIXME Sequences not treated yet !
//
// Ne faudrait-il pas au contraire trouver immediatement
// une maniere 'propre' de traiter les sequences (vr = SQ)
// car commencer par les ignorer risque de conduire a qq chose
// qui pourrait ne pas etre generalisable
- //
+ // Well, I'm expecting your code !!!
+
if( vr == "SQ" )
SkipLoad = true;
if( group == 0xfffe )
SkipLoad = true;
- // The group length doesn't represent data to be loaded in memory, since
- // each element of the group shall be loaded individualy.
- if( elem == 0 )
- //SkipLoad = true; // modif sauvage JPR
- // On charge la longueur du groupe
- // quand l'element 0x0000 est présent !
-
if ( SkipLoad ) {
- // FIXME the following skip is not necessary
- SkipElementValue(ElVal);
ElVal->SetLength(0);
ElVal->SetValue("gdcm::Skipped");
return;
// pour les elements de Value Multiplicity > 1
// on aura en fait une serie d'entiers
- // code original
-
- //if ( IsAnInteger(ElVal) ) {
- // guint32 NewInt;
- // if( length == 2 ) {
- // NewInt = ReadInt16();
- // } else if( length == 4 ) {
- //
- // NewInt = ReadInt32();
- // } else
- // dbg.Error(true, "LoadElementValue: Inconsistency when reading Int.");
- //
- // //FIXME: make the following an util fonction
- // ostringstream s;
- // s << NewInt;
- // ElVal->SetValue(s.str());
- // return;
- //}
-
- // modif proposee. JPR
// on devrait pouvoir faire + compact (?)
if ( IsAnInteger(ElVal) ) {
s << '\\';
NewInt = ReadInt16();
s << NewInt;
- //printf("%s\n", s.str().c_str());
}
}
return;
}
-
-
- // FIXME The exact size should be length if we move to strings or whatever
+ // We need an additional byte for storing \0 that is not on disk
char* NewValue = (char*)malloc(length+1);
if( !NewValue) {
dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue");
return;
}
ElVal->SetValue(NewValue);
+ free(NewValue);
}
/**
* @param ElVal Element whose value shall be loaded.
* @return
*/
-void gdcmHeader::LoadElementValueSafe(ElValue * ElVal) {
+void gdcmHeader::LoadElementValueSafe(gdcmElValue * ElVal) {
long PositionOnEntry = ftell(fp);
LoadElementValue(ElVal);
fseek(fp, PositionOnEntry, SEEK_SET);
return g;
}
+
+gdcmElValue* gdcmHeader::GetElValueByNumber(guint16 Group, guint16 Elem) {
+
+ gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem);
+ if (!elValue) {
+ dbg.Verbose(1, "gdcmHeader::GetElValueByNumber",
+ "failed to Locate gdcmElValue");
+ return (gdcmElValue*)0;
+ }
+ return elValue;
+}
+
/**
* \ingroup gdcmHeader
* \brief Build a new Element Value from all the low level arguments.
* @param Group group of the underlying DictEntry
* @param Elem element of the underlying DictEntry
*/
-ElValue* gdcmHeader::NewElValueByKey(guint16 Group, guint16 Elem) {
+gdcmElValue* gdcmHeader::NewElValueByNumber(guint16 Group, guint16 Elem) {
// Find out if the tag we encountered is in the dictionaries:
- gdcmDictEntry * NewTag = GetDictEntryByKey(Group, Elem);
+ gdcmDictEntry * NewTag = GetDictEntryByNumber(Group, Elem);
if (!NewTag)
NewTag = new gdcmDictEntry(Group, Elem);
- ElValue* NewElVal = new ElValue(NewTag);
+ gdcmElValue* NewElVal = new gdcmElValue(NewTag);
if (!NewElVal) {
- dbg.Verbose(1, "gdcmHeader::NewElValueByKey",
- "failed to allocate ElValue");
- return (ElValue*)0;
+ dbg.Verbose(1, "gdcmHeader::NewElValueByNumber",
+ "failed to allocate gdcmElValue");
+ return (gdcmElValue*)0;
}
return NewElVal;
}
+/**
+ * \ingroup gdcmHeader
+ * \brief TODO
+ * @param
+ */
+int gdcmHeader::ReplaceOrCreateByNumber(string Value, guint16 Group, guint16 Elem ) {
+
+ gdcmElValue* nvElValue=NewElValueByNumber(Group, Elem);
+ PubElValSet.Add(nvElValue);
+ PubElValSet.SetElValueByNumber(Value, Group, Elem);
+ return(1);
+}
+
+
/**
* \ingroup gdcmHeader
* \brief Build a new Element Value from all the low level arguments.
* a default one when absent.
* @param Name Name of the underlying DictEntry
*/
-ElValue* gdcmHeader::NewElValueByName(string Name) {
+gdcmElValue* gdcmHeader::NewElValueByName(string Name) {
gdcmDictEntry * NewTag = GetDictEntryByName(Name);
if (!NewTag)
NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name);
- ElValue* NewElVal = new ElValue(NewTag);
+ gdcmElValue* NewElVal = new gdcmElValue(NewTag);
if (!NewElVal) {
dbg.Verbose(1, "gdcmHeader::ObtainElValueByName",
- "failed to allocate ElValue");
- return (ElValue*)0;
+ "failed to allocate gdcmElValue");
+ return (gdcmElValue*)0;
}
return NewElVal;
}
* \brief Read the next tag but WITHOUT loading it's value
* @return On succes the newly created ElValue, NULL on failure.
*/
-ElValue * gdcmHeader::ReadNextElement(void) {
- guint16 g;
- guint16 n;
- ElValue * NewElVal;
+gdcmElValue * gdcmHeader::ReadNextElement(void) {
+
+ guint16 g,n;
+ gdcmElValue * NewElVal;
g = ReadInt16();
n = ReadInt16();
if (errno == 1)
// We reached the EOF (or an error occured) and header parsing
// has to be considered as finished.
- return (ElValue *)0;
+ return (gdcmElValue *)0;
- NewElVal = NewElValueByKey(g, n);
+ NewElVal = NewElValueByNumber(g, n);
FindVR(NewElVal);
FindLength(NewElVal);
if (errno == 1)
// Call it quits
- return (ElValue *)0;
+ return (gdcmElValue *)0;
NewElVal->SetOffset(ftell(fp));
return NewElVal;
}
* @param ElVal The element value on which to apply the predicate.
* @return The result of the heuristical predicate.
*/
-bool gdcmHeader::IsAnInteger(ElValue * ElVal) {
+bool gdcmHeader::IsAnInteger(gdcmElValue * ElVal) {
guint16 group = ElVal->GetGroup();
guint16 element = ElVal->GetElement();
string vr = ElVal->GetVR();
if ( element == 0 ) { // This is the group length of the group
if (length == 4)
return true;
- else
+ else {
+ printf("Erroneous Group Length element length (%04x , %04x) : %d\n",
+ group, element,length);
+
dbg.Error("gdcmHeader::IsAnInteger",
- "Erroneous Group Length element length.");
+ "Erroneous Group Length element length.");
+ }
}
- /*
- // on le traite tt de même (VR peut donner l'info)
- // faire qq chose + ruse (pas de test si pas de VR)
- if ( group % 2 != 0 )
- // We only have some semantics on documented elements, which are
- // the even ones.
- return false;
- */
-
- /*
- if ( (length != 4) && ( length != 2) )
- // Swapping only make sense on integers which are 2 or 4 bytes long.
-
- // En fait, pour les entiers de 'Value Multiplicity' supérieur a 1
- // la longueur n'est pas forcement 2 ou 4
- // ET il faudra swapper.
- return false;
- */
-
if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") )
return true;
-
- // est-ce encore utile?
- // mieux vaut modifier le source du Dicom Dictionnaty
- // et remplacer pour ces 2 cas RET par US
-
- if ( (group == 0x0028) && (element == 0x0005) )
- // The "Image Dimensions" tag is retained from ACR/NEMA and contains
- // the number of dimensions of the contained object (1 for Signal,
- // 2 for Image, 3 for Volume, 4 for Sequence).
- return true;
-
- if ( (group == 0x0028) && (element == 0x0200) )
- // This tag is retained from ACR/NEMA
- return true;
-
return false;
}
// is found by indirection through the "Image Location").
// Inside the group pointed by "Image Location" the searched element
// is conventionally the element 0x0010 (when the norm is respected).
- // When the "Image Location" is absent we default to group 0x7fe0.
+ // When the "Image Location" is absent we default to group 0x7fe0.
guint16 grPixel;
guint16 numPixel;
string ImageLocation = GetPubElValByName("Image Location");
grPixel = (guint16) atoi( ImageLocation.c_str() );
}
if (grPixel != 0x7fe0)
- // FIXME is this still necessary ?
- // Now, this looks like an old dirty fix for Philips imager
+ // This is a kludge for old dirty Philips imager.
numPixel = 0x1010;
else
numPixel = 0x0010;
- ElValue* PixelElement = PubElVals.GetElementByNumber(grPixel, numPixel);
+ gdcmElValue* PixelElement = PubElValSet.GetElementByNumber(grPixel,
+ numPixel);
if (PixelElement)
return PixelElement->GetOffset();
else
* @param element element of the searched DictEntry
* @return Corresponding DictEntry when it exists, NULL otherwise.
*/
-gdcmDictEntry * gdcmHeader::GetDictEntryByKey(guint16 group, guint16 element) {
+gdcmDictEntry * gdcmHeader::GetDictEntryByNumber(guint16 group,
+ guint16 element) {
gdcmDictEntry * found = (gdcmDictEntry*)0;
if (!RefPubDict && !RefShaDict) {
- dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry",
+ dbg.Verbose(0, "gdcmHeader::GetDictEntry",
"we SHOULD have a default dictionary");
}
if (RefPubDict) {
- found = RefPubDict->GetTagByKey(group, element);
+ found = RefPubDict->GetTagByNumber(group, element);
if (found)
return found;
}
if (RefShaDict) {
- found = RefShaDict->GetTagByKey(group, element);
+ found = RefShaDict->GetTagByNumber(group, element);
if (found)
return found;
}
gdcmDictEntry * gdcmHeader::GetDictEntryByName(string Name) {
gdcmDictEntry * found = (gdcmDictEntry*)0;
if (!RefPubDict && !RefShaDict) {
- dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry",
+ dbg.Verbose(0, "gdcmHeader::GetDictEntry",
"we SHOULD have a default dictionary");
}
if (RefPubDict) {
* "gdcm::Unfound" otherwise.
*/
string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) {
- return PubElVals.GetElValueByNumber(group, element);
+ return PubElValSet.GetElValueByNumber(group, element);
}
/**
* and the string "gdcm::Unfound" otherwise.
*/
string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) {
- ElValue* elem = PubElVals.GetElementByNumber(group, element);
+ gdcmElValue* elem = PubElValSet.GetElementByNumber(group, element);
if ( !elem )
return "gdcm::Unfound";
return elem->GetVR();
* "gdcm::Unfound" otherwise.
*/
string gdcmHeader::GetPubElValByName(string TagName) {
- return PubElVals.GetElValueByName(TagName);
+ return PubElValSet.GetElValueByName(TagName);
}
/**
* and the string "gdcm::Unfound" otherwise.
*/
string gdcmHeader::GetPubElValRepByName(string TagName) {
- ElValue* elem = PubElVals.GetElementByName(TagName);
+ gdcmElValue* elem = PubElValSet.GetElementByName(TagName);
if ( !elem )
return "gdcm::Unfound";
return elem->GetVR();
* and the string "gdcm::Unfound" otherwise.
*/
string gdcmHeader::GetShaElValByNumber(guint16 group, guint16 element) {
- return ShaElVals.GetElValueByNumber(group, element);
+ return ShaElValSet.GetElValueByNumber(group, element);
}
/**
* and the string "gdcm::Unfound" otherwise.
*/
string gdcmHeader::GetShaElValRepByNumber(guint16 group, guint16 element) {
- ElValue* elem = ShaElVals.GetElementByNumber(group, element);
+ gdcmElValue* elem = ShaElValSet.GetElementByNumber(group, element);
if ( !elem )
return "gdcm::Unfound";
return elem->GetVR();
* "gdcm::Unfound" otherwise.
*/
string gdcmHeader::GetShaElValByName(string TagName) {
- return ShaElVals.GetElValueByName(TagName);
+ return ShaElValSet.GetElValueByName(TagName);
}
/**
* and the string "gdcm::Unfound" otherwise.
*/
string gdcmHeader::GetShaElValRepByName(string TagName) {
- ElValue* elem = ShaElVals.GetElementByName(TagName);
+ gdcmElValue* elem = ShaElValSet.GetElementByName(TagName);
if ( !elem )
return "gdcm::Unfound";
return elem->GetVR();
/**
* \ingroup gdcmHeader
- * \brief Accesses an existing ElValue in the PubElVals of this instance
+ * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance
* through it's (group, element) and modifies it's content with
* the given value.
* @param content new value to substitute with
*/
int gdcmHeader::SetPubElValByNumber(string content, guint16 group,
guint16 element)
+
+//TODO : homogeneiser les noms : SetPubElValByNumber qui appelle PubElValSet.SetElValueByNumber
+// pourquoi pas SetPubElValueByNumber ??
{
- return ( PubElVals.SetElValueByNumber (content, group, element) );
+
+ return ( PubElValSet.SetElValueByNumber (content, group, element) );
}
/**
* \ingroup gdcmHeader
- * \brief Accesses an existing ElValue in the PubElVals of this instance
+ * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance
* through tag name and modifies it's content with the given value.
* @param content new value to substitute with
* @param TagName name of the tag to be modified
*/
int gdcmHeader::SetPubElValByName(string content, string TagName) {
- return ( PubElVals.SetElValueByName (content, TagName) );
+ return ( PubElValSet.SetElValueByName (content, TagName) );
}
/**
* \ingroup gdcmHeader
- * \brief Accesses an existing ElValue in the PubElVals of this instance
+ * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance
* through it's (group, element) and modifies it's length with
* the given value.
- * NOT FOR BOZOs !
- * @param contents new length to substitute with
+ * \warning Use with extreme caution.
+ * @param length new length to substitute with
* @param group group of the ElVal to modify
* @param element element of the ElVal to modify
+ * @return 1 on success, 0 otherwise.
*/
-int gdcmHeader::SetPubElValLengthByNumber(guint32 lgr, guint16 group,
- guint16 element)
-{
- return ( PubElVals.SetElValueLengthByNumber (lgr, group, element) );
+
+int gdcmHeader::SetPubElValLengthByNumber(guint32 length, guint16 group,
+ guint16 element) {
+ return ( PubElValSet.SetElValueLengthByNumber (length, group, element) );
}
/**
* \ingroup gdcmHeader
- * \brief Accesses an existing ElValue in the ShaElVals of this instance
+ * \brief Accesses an existing gdcmElValue in the ShaElValSet of this instance
* through it's (group, element) and modifies it's content with
* the given value.
* @param content new value to substitute with
* @param group group of the ElVal to modify
* @param element element of the ElVal to modify
+ * @return 1 on success, 0 otherwise.
*/
int gdcmHeader::SetShaElValByNumber(string content,
- guint16 group, guint16 element)
-{
- return ( ShaElVals.SetElValueByNumber (content, group, element) );
+ guint16 group, guint16 element) {
+ return ( ShaElValSet.SetElValueByNumber (content, group, element) );
}
-
-
-
/**
* \ingroup gdcmHeader
- * \brief Accesses an existing ElValue in the ShaElVals of this instance
+ * \brief Accesses an existing gdcmElValue in the ShaElValSet of this instance
* through tag name and modifies it's content with the given value.
* @param content new value to substitute with
* @param TagName name of the tag to be modified
*/
int gdcmHeader::SetShaElValByName(string content, string TagName) {
- return ( ShaElVals.SetElValueByName (content, TagName) );
+ return ( ShaElValSet.SetElValueByName (content, TagName) );
}
/**
* \brief Parses the header of the file but WITHOUT loading element values.
*/
void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) {
- ElValue * newElValue = (ElValue *)0;
+ gdcmElValue * newElValue = (gdcmElValue *)0;
rewind(fp);
CheckSwap();
while ( (newElValue = ReadNextElement()) ) {
SkipElementValue(newElValue);
- PubElVals.Add(newElValue);
+ PubElValSet.Add(newElValue);
}
}
/**
* \ingroup gdcmHeader
- * \brief Once the header is parsed add some gdcm convenience/helper elements
- * in the ElValSet. For example add:
- * - gdcmImageType which is an entry containing a short for the
- * type of image and whose value ranges in
- * I8 (unsigned 8 bit image)
- * I16 (unsigned 8 bit image)
- * IS16 (signed 8 bit image)
- * - gdcmXsize, gdcmYsize, gdcmZsize whose values are respectively
- * the ones of the official DICOM fields Rows, Columns and Planes.
+ * \brief Retrieve the number of columns of image.
+ * @return The encountered size when found, 0 by default.
*/
-void gdcmHeader::AddAndDefaultElements(void) {
- ElValue* NewEntry = (ElValue*)0;
+int gdcmHeader::GetXSize(void) {
+ // We cannot check for "Columns" because the "Columns" tag is present
+ // both in IMG (0028,0011) and OLY (6000,0011) sections of the dictionary.
+ string StrSize = GetPubElValByNumber(0x0028,0x0011);
+ if (StrSize == "gdcm::Unfound")
+ return 0;
+ return atoi(StrSize.c_str());
+}
- NewEntry = NewElValueByName("gdcmXSize");
- NewEntry->SetValue(GetElValByName("Rows"));
- PubElVals.Add(NewEntry);
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the number of lines of image.
+ * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize()
+ * @return The encountered size when found, 1 by default.
+ */
+int gdcmHeader::GetYSize(void) {
+ // We cannot check for "Rows" because the "Rows" tag is present
+ // both in IMG (0028,0010) and OLY (6000,0010) sections of the dictionary.
+ string StrSize = GetPubElValByNumber(0x0028,0x0010);
+ if (StrSize != "gdcm::Unfound")
+ return atoi(StrSize.c_str());
+ if ( IsDicomV3() )
+ return 0;
+ else
+ // The Rows (0028,0010) entry is optional for ACR/NEMA. It might
+ // hence be a signal (1d image). So we default to 1:
+ return 1;
+}
- NewEntry = NewElValueByName("gdcmYSize");
- NewEntry->SetValue(GetElValByName("Columns"));
- PubElVals.Add(NewEntry);
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the number of planes of volume or the number
+ * of frames of a multiframe.
+ * \warning When present we consider the "Number of Frames" as the third
+ * dimension. When absent we consider the third dimension as
+ * being the "Planes" tag content.
+ * @return The encountered size when found, 1 by default.
+ */
+int gdcmHeader::GetZSize(void) {
+ // Both in DicomV3 and ACR/Nema the consider the "Number of Frames"
+ // as the third dimension.
+ string StrSize = GetPubElValByNumber(0x0028,0x0008);
+ if (StrSize != "gdcm::Unfound")
+ return atoi(StrSize.c_str());
+
+ // We then consider the "Planes" entry as the third dimension [we
+ // cannot retrieve by name since "Planes tag is present both in
+ // IMG (0028,0012) and OLY (6000,0012) sections of the dictionary].
+ StrSize = GetPubElValByNumber(0x0028,0x0012);
+ if (StrSize != "gdcm::Unfound")
+ return atoi(StrSize.c_str());
+ return 1;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Return the size (in bytes) of a single pixel of data.
+ * @return The size in bytes of a single pixel of data.
+ *
+ */
+int gdcmHeader::GetPixelSize(void) {
+ string PixelType = GetPixelType();
+ if (PixelType == "8U" || PixelType == "8S")
+ return 1;
+ if (PixelType == "16U" || PixelType == "16S")
+ return 2;
+ if (PixelType == "32U" || PixelType == "32S")
+ return 4;
+ dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type");
+ return 0;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Build the Pixel Type of the image.
+ * Possible values are:
+ * - 8U unsigned 8 bit,
+ * - 8S signed 8 bit,
+ * - 16U unsigned 16 bit,
+ * - 16S signed 16 bit,
+ * - 32U unsigned 32 bit,
+ * - 32S signed 32 bit,
+ * \warning 12 bit images appear as 16 bit.
+ * @return
+ */
+string gdcmHeader::GetPixelType(void) {
+ string BitsAlloc;
+ BitsAlloc = GetElValByName("Bits Allocated");
+ if (BitsAlloc == "gdcm::Unfound") {
+ dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
+ BitsAlloc = string("16");
+ }
+ if (BitsAlloc == "12")
+ BitsAlloc = string("16");
+
+ string Signed;
+ Signed = GetElValByName("Pixel Representation");
+ if (Signed == "gdcm::Unfound") {
+ dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
+ BitsAlloc = string("0");
+ }
+ if (Signed == "0")
+ Signed = string("U");
+ else
+ Signed = string("S");
+
+ return( BitsAlloc + Signed);
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief This predicate, based on hopefully reasonnable heuristics,
+ * decides whether or not the current gdcmHeader was properly parsed
+ * and contains the mandatory information for being considered as
+ * a well formed and usable image.
+ * @return true when gdcmHeader is the one of a reasonable Dicom file,
+ * false otherwise.
+ */
+bool gdcmHeader::IsReadable(void) {
+ if ( GetElValByName("Image Dimensions") != "gdcm::Unfound"
+ && atoi(GetElValByName("Image Dimensions").c_str()) > 4 ) {
+ return false;
+ }
+ if ( GetElValByName("Bits Allocated") == "gdcm::Unfound" )
+ return false;
+ if ( GetElValByName("Bits Stored") == "gdcm::Unfound" )
+ return false;
+ if ( GetElValByName("High Bit") == "gdcm::Unfound" )
+ return false;
+ if ( GetElValByName("Pixel Representation") == "gdcm::Unfound" )
+ return false;
+ return true;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Small utility function that creates a new manually crafted
+ * (as opposed as read from the file) gdcmElValue with user
+ * specified name and adds it to the public tag hash table.
+ * \note A fake TagKey is generated so the PubDict can keep it's coherence.
+ * @param NewTagName The name to be given to this new tag.
+ * @param VR The Value Representation to be given to this new tag.
+ * @ return The newly hand crafted Element Value.
+ */
+gdcmElValue* gdcmHeader::NewManualElValToPubDict(string NewTagName, string VR) {
+ gdcmElValue* NewElVal = (gdcmElValue*)0;
+ guint32 StuffGroup = 0xffff; // Group to be stuffed with additional info
+ guint32 FreeElem = 0;
+ gdcmDictEntry* NewEntry = (gdcmDictEntry*)0;
+
+ FreeElem = PubElValSet.GenerateFreeTagKeyInGroup(StuffGroup);
+ if (FreeElem == UINT32_MAX) {
+ dbg.Verbose(1, "gdcmHeader::NewManualElValToPubDict",
+ "Group 0xffff in Public Dict is full");
+ return (gdcmElValue*)0;
+ }
+ NewEntry = new gdcmDictEntry(StuffGroup, FreeElem,
+ VR, "GDCM", NewTagName);
+ NewElVal = new gdcmElValue(NewEntry);
+ PubElValSet.Add(NewElVal);
+ return NewElVal;
- NewEntry = NewElValueByName("gdcmZSize");
- NewEntry->SetValue(GetElValByName("Planes"));
- PubElVals.Add(NewEntry);
}
/**
*/
void gdcmHeader::LoadElements(void) {
rewind(fp);
- TagElValueHT ht = PubElVals.GetTagHt();
+ TagElValueHT ht = PubElValSet.GetTagHt();
for (TagElValueHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) {
LoadElementValue(tag->second);
}
}
void gdcmHeader::PrintPubElVal(ostream & os) {
- PubElVals.Print(os);
+ PubElValSet.Print(os);
}
void gdcmHeader::PrintPubDict(ostream & os) {
RefPubDict->Print(os);
}
+
+int gdcmHeader::Write(FILE * fp, FileType type) {
+ return PubElValSet.Write(fp, type);
+}