📄 gdcmfile.cxx
字号:
/*=========================================================================
Program: gdcm
Module: $RCSfile: gdcmFile.cxx,v $
Language: C++
Date: $Date: 2008-05-14 12:25:32 $
Version: $Revision: 1.24 $
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.
=========================================================================*/
#if defined(__BORLANDC__)
#pragma warn -8004 /* assigned a value that is never used */
#endif
//
// -------------- Remember ! ----------------------------------
//
// Image Position (Patient) (0020,0032):
// If not found (ACR_NEMA) we try Image Position (0020,0030)
// If not found (ACR-NEMA), we consider Slice Location (0020,1041)
// or Location (0020,0050)
// as the Z coordinate,
// 0. for all the coordinates if nothing is found
//
// Image Position (Patient) (0020,0032) VM=3
// -->
// The attribute Patient Orientation (0020,0020) from the General Image Module
// is of type 2C and has the condition Required if image does not require
// Image Orientation (0020,0037) and Image Position (0020,0032).
// However, if the image does require the attributes
// - Image Orientation (Patient) (0020,0037), VM=6
// - Image Position (Patient) (0020,0032), VM=3
// then attribute Patient Orientation (0020,0020) should not be present
// in the images.
//
// Remember also :
// Patient Position (0018,5100) values :
// HFS = Head First-Supine, where increasing (positive axis direction) :
// X -> to the direction pointed to by the patient's oustretched left arm
// Y -> to the anterior-to-posterior direction in the patient's body
// Z -> to the feet-to-head direction in the patient's body
// HFP = Head First-Prone, where increasing (positive axis direction) :
// X -> to the direction pointed to by the patient's oustretched left arm
// Y -> to the anterior-to-posterior direction in the patient's body
// Z -> to the feet-to-head direction in the patient's body
// FFS = Feet First-Supine, where increasing (positive axis direction) :
// X -> to the direction pointed to by the patient's oustretched left arm
// Y -> to the anterior-to-posterion direction in the patient's body
// Z -> to the feet-to-head direction in the patient's body
// FFP = Feet First-Prone, where increasing (positive axis direction) :
// X -> to the direction pointed to by the patient's oustretched left arm
// Y -> to the posterior-to-anterior direction in the patient's body
// Z -> to the feet-to-head direction in the patient's body
// HFDR = Head First-Decubitus Right
// HFDL = Head First-Decubitus Left
// FFDR = Feet First-Decubitus Right
// FFDL = Feet First-Decubitus Left
// we can also find (non standard!)
// SEMIERECT
// SUPINE
// CS 2 Patient Orientation (0020 0020)
// When the coordinates of the image
// are always present, this field is almost never used.
// Better we don't trust it too much ...
// Found Values are :
// L\P
// L\FP
// P\F
// L\F
// P\FR
// R\F
//
// (0020|0037) [Image Orientation (Patient)] [1\0\0\0\1\0 ]
// ---------------------------------------------------------------
//
#include "gdcmFile.h"
#include "gdcmGlobal.h"
#include "gdcmUtil.h"
#include "gdcmDebug.h"
#include "gdcmTS.h"
#include "gdcmValEntry.h"
#include "gdcmBinEntry.h"
#include "gdcmSeqEntry.h"
#include "gdcmRLEFramesInfo.h"
#include "gdcmJPEGFragmentsInfo.h"
#include "gdcmSQItem.h"
#include <vector>
#include <stdio.h> //sscanf
#include <stdlib.h> // for atoi
namespace gdcm
{
//-----------------------------------------------------------------------------
// Constructor / Destructor
/**
* \brief Constructor used when we want to generate dicom files from scratch
*/
File::File():
Document()
{
RLEInfo = new RLEFramesInfo;
JPEGInfo = new JPEGFragmentsInfo;
GrPixel = 0x7fe0; // to avoid further troubles
NumPixel = 0x0010;
BasicOffsetTableItemValue = 0;
}
/**
* \brief Canonical destructor.
*/
File::~File()
{
if ( RLEInfo )
delete RLEInfo;
if ( JPEGInfo )
delete JPEGInfo;
delete[] BasicOffsetTableItemValue;
}
//-----------------------------------------------------------------------------
// Public
/**
* \brief Loader
* @return false if file cannot be open or no swap info was found,
* or no tag was found.
*/
bool File::Load( )
{
if ( ! this->Document::Load( ) )
return false;
return DoTheLoadingJob( );
}
/**
* \brief Does 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 File::DoTheLoadingJob( )
{
// for some ACR-NEMA images GrPixel, NumPixel is *not* 7fe0,0010
// We may encounter the 'RETired' (0x0028, 0x0200) tag
// (Image Location") . This entry contains the number of
// the group that contains the pixel data (hence the "Pixel Data"
// 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 missing we default to group 0x7fe0.
// Note: this IS the right place for the code
// Image Location
const std::string &imgLocation = GetEntryValue(0x0028, 0x0200);
if ( imgLocation == GDCM_UNFOUND || imgLocation == GDCM_BINLOADED )
{
// default value
GrPixel = 0x7fe0;
}
else
{
GrPixel = (uint16_t) atoi( imgLocation.c_str() );
}
// sometimes Image Location value doesn't follow
// the supposed processor endianness.
// see gdcmData/cr172241.dcm
if ( GrPixel == 0xe07f )
{
GrPixel = 0x7fe0;
}
if ( GrPixel != 0x7fe0 )
{
// This is a kludge for old dirty Philips imager.
NumPixel = 0x1010;
}
else
{
NumPixel = 0x0010;
}
// Now, we know GrPixel and NumPixel.
// Let's create a VirtualDictEntry to allow a further VR modification
// and force VR to match with BitsAllocated.
DocEntry *entry = GetDocEntry(GrPixel, NumPixel);
if ( entry != 0 )
{
// Compute the RLE or JPEG info
OpenFile();
const std::string &ts = GetTransferSyntax();
Fp->seekg( entry->GetOffset(), std::ios::beg );
if ( Global::GetTS()->IsRLELossless(ts) )
ComputeRLEInfo();
else if ( Global::GetTS()->IsJPEG(ts) )
ComputeJPEGFragmentInfo();
CloseFile();
// Create a new BinEntry to change the DictEntry
// The changed DictEntry will have
// - a correct PixelVR OB or OW)
// - the name to "Pixel Data"
BinEntry *oldEntry = dynamic_cast<BinEntry *>(entry);
if (oldEntry)
{
std::string PixelVR;
// 8 bits allocated is a 'O Bytes' , as well as 24 (old ACR-NEMA RGB)
// more than 8 (i.e 12, 16) is a 'O Words'
if ( GetBitsAllocated() == 8 || GetBitsAllocated() == 24 )
PixelVR = "OB";
else
PixelVR = "OW";
// Change only made if usefull
if ( PixelVR != oldEntry->GetVR() )
{
DictEntry* newDict = NewVirtualDictEntry(GrPixel,NumPixel,
PixelVR,"1","Pixel Data");
BinEntry *newEntry = new BinEntry(newDict);
newEntry->Copy(entry);
newEntry->SetBinArea(oldEntry->GetBinArea(),oldEntry->IsSelfArea());
oldEntry->SetSelfArea(false);
RemoveEntry(oldEntry);
AddEntry(newEntry);
}
}
}
return true;
}
/**
* \brief This predicate, based on hopefully reasonable heuristics,
* decides whether or not the current File was properly parsed
* and contains the mandatory information for being considered as
* a well formed and usable Dicom/Acr File.
* @return true when File is the one of a reasonable Dicom/Acr file,
* false otherwise.
*/
bool File::IsReadable()
{
if ( !Document::IsReadable() )
{
return false;
}
const std::string &res = GetEntryValue(0x0028, 0x0005);
if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 )
{
gdcmWarningMacro("Wrong Image Dimensions" << res);
return false; // Image Dimensions
}
bool b0028_0100 = true;
if ( !GetDocEntry(0x0028, 0x0100) )
{
gdcmWarningMacro("Bits Allocated (0028|0100) not found");
//return false; // "Bits Allocated"
b0028_0100 = false;
}
bool b0028_0101 = true;
if ( !GetDocEntry(0x0028, 0x0101) )
{
gdcmWarningMacro("Bits Stored (0028|0101) not found");
//return false; // "Bits Stored"
b0028_0101 = false;
}
bool b0028_0102 = true;
if ( !GetDocEntry(0x0028, 0x0102) )
{
gdcmWarningMacro("Hight Bit (0028|0102) not found");
//return false; // "High Bit"
b0028_0102 = false;
}
bool b0028_0103 = true;
if ( !GetDocEntry(0x0028, 0x0103) )
{
gdcmWarningMacro("Pixel Representation (0028|0103) not found");
//return false; // "Pixel Representation" i.e. 'Sign' ( 0 : unsigned, 1 : signed)
b0028_0103 = false;
}
if ( !b0028_0100 && !b0028_0101 && !b0028_0102 && !b0028_0103)
{
gdcmWarningMacro("Too much mandatory Tags missing !");
return false;
}
if ( !GetDocEntry(GrPixel, NumPixel) )
{
gdcmWarningMacro("Pixel Dicom Element " << std::hex <<
GrPixel << "|" << NumPixel << "not found");
return false; // Pixel Dicom Element not found :-(
}
return true;
}
/**
* \brief gets the info from 0020,0013 : Image Number else 0.
* @return image number
*/
int File::GetImageNumber()
{
//0020 0013 : Image Number
std::string strImNumber = GetEntryValue(0x0020,0x0013);
if ( strImNumber != GDCM_UNFOUND )
{
return atoi( strImNumber.c_str() );
}
return 0; //Hopeless
}
/**
* \brief gets the info from 0008,0060 : Modality
* @return Modality Type
*/
ModalityType File::GetModality()
{
// 0008 0060 : Modality
std::string strModality = GetEntryValue(0x0008,0x0060);
if ( strModality != GDCM_UNFOUND )
{
if ( strModality.find("AU") < strModality.length()) return AU;
else if ( strModality.find("AS") < strModality.length()) return AS;
else if ( strModality.find("BI") < strModality.length()) return BI;
else if ( strModality.find("CF") < strModality.length()) return CF;
else if ( strModality.find("CP") < strModality.length()) return CP;
else if ( strModality.find("CR") < strModality.length()) return CR;
else if ( strModality.find("CT") < strModality.length()) return CT;
else if ( strModality.find("CS") < strModality.length()) return CS;
else if ( strModality.find("DD") < strModality.length()) return DD;
else if ( strModality.find("DF") < strModality.length()) return DF;
else if ( strModality.find("DG") < strModality.length()) return DG;
else if ( strModality.find("DM") < strModality.length()) return DM;
else if ( strModality.find("DS") < strModality.length()) return DS;
else if ( strModality.find("DX") < strModality.length()) return DX;
else if ( strModality.find("ECG") < strModality.length()) return ECG;
else if ( strModality.find("EPS") < strModality.length()) return EPS;
else if ( strModality.find("FA") < strModality.length()) return FA;
else if ( strModality.find("FS") < strModality.length()) return FS;
else if ( strModality.find("HC") < strModality.length()) return HC;
else if ( strModality.find("HD") < strModality.length()) return HD;
else if ( strModality.find("LP") < strModality.length()) return LP;
else if ( strModality.find("LS") < strModality.length()) return LS;
else if ( strModality.find("MA") < strModality.length()) return MA;
else if ( strModality.find("MR") < strModality.length()) return MR;
else if ( strModality.find("NM") < strModality.length()) return NM;
else if ( strModality.find("OT") < strModality.length()) return OT;
else if ( strModality.find("PT") < strModality.length()) return PT;
else if ( strModality.find("RF") < strModality.length()) return RF;
else if ( strModality.find("RG") < strModality.length()) return RG;
else if ( strModality.find("RTDOSE")
< strModality.length()) return RTDOSE;
else if ( strModality.find("RTIMAGE")
< strModality.length()) return RTIMAGE;
else if ( strModality.find("RTPLAN")
< strModality.length()) return RTPLAN;
else if ( strModality.find("RTSTRUCT")
< strModality.length()) return RTSTRUCT;
else if ( strModality.find("SM") < strModality.length()) return SM;
else if ( strModality.find("ST") < strModality.length()) return ST;
else if ( strModality.find("TG") < strModality.length()) return TG;
else if ( strModality.find("US") < strModality.length()) return US;
else if ( strModality.find("VF") < strModality.length()) return VF;
else if ( strModality.find("XA") < strModality.length()) return XA;
else if ( strModality.find("XC") < strModality.length()) return XC;
else
{
/// \todo throw error return value ???
/// specified <> unknown in our database
return Unknow;
}
}
return Unknow;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -