You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1388 lines
46 KiB
1388 lines
46 KiB
/*=========================================================================
|
|
|
|
Program: DICOMParser
|
|
Module: $RCSfile: DICOMAppHelper.cxx,v $
|
|
Language: C++
|
|
Date: $Date: 2006/08/31 17:30:29 $
|
|
Version: $Revision: 1.21.20.2 $
|
|
|
|
Copyright (c) 2003 Matt Turek
|
|
All rights reserved.
|
|
See Copyright.txt 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 notice for more information.
|
|
|
|
=========================================================================*/
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning ( disable : 4514 )
|
|
#pragma warning ( disable : 4786 )
|
|
#pragma warning ( disable : 4503 )
|
|
#pragma warning ( disable : 4710 )
|
|
#pragma warning ( disable : 4702 )
|
|
#pragma warning ( push, 3 )
|
|
#endif
|
|
|
|
#include "DICOMConfig.h"
|
|
#include "DICOMAppHelper.h"
|
|
#include "DICOMCallback.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <algorithm>
|
|
#if defined(__BORLANDC__)
|
|
#include <mem.h> // for memcpy
|
|
#endif
|
|
|
|
//#define DEBUG_DICOM_APP_HELPER
|
|
|
|
class DICOMAppHelperImplementation
|
|
{
|
|
public:
|
|
// map from series UID to vector of files in the series
|
|
dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr> SeriesUIDMap;
|
|
|
|
// map from filename to intraseries sortable tags
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr> SliceOrderingMap;
|
|
|
|
typedef dicom_stl::map<dicom_stl::pair<doublebyte, doublebyte>, DICOMTagInfo> TagMapType;
|
|
TagMapType TagMap;
|
|
|
|
};
|
|
|
|
struct lt_pair_int_string
|
|
{
|
|
bool operator()(const dicom_stl::pair<int, dicom_stl::string> s1,
|
|
const dicom_stl::pair<int, dicom_stl::string> s2) const
|
|
{
|
|
return s1.first < s2.first;
|
|
}
|
|
};
|
|
|
|
|
|
struct lt_pair_float_string
|
|
{
|
|
bool operator()(const dicom_stl::pair<float, dicom_stl::string> s1,
|
|
const dicom_stl::pair<float, dicom_stl::string> s2) const
|
|
{
|
|
return s1.first < s2.first;
|
|
}
|
|
};
|
|
|
|
|
|
struct gt_pair_int_string
|
|
{
|
|
bool operator()(const dicom_stl::pair<int, dicom_stl::string> s1,
|
|
const dicom_stl::pair<int, dicom_stl::string> s2) const
|
|
{
|
|
return s1.first > s2.first;
|
|
}
|
|
};
|
|
|
|
|
|
struct gt_pair_float_string
|
|
{
|
|
bool operator()(const dicom_stl::pair<float, dicom_stl::string> s1,
|
|
const dicom_stl::pair<float, dicom_stl::string> s2) const
|
|
{
|
|
return s1.first > s2.first;
|
|
}
|
|
};
|
|
|
|
|
|
DICOMAppHelper::DICOMAppHelper()
|
|
{
|
|
this->BitsAllocated = 8;
|
|
this->ByteSwapData = false;
|
|
this->PixelSpacing[0] = this->PixelSpacing[1] = this->PixelSpacing[2] = 1.0;
|
|
this->Dimensions[0] = this->Dimensions[1] = 0;
|
|
this->PhotometricInterpretation = new dicom_stl::string();
|
|
this->TransferSyntaxUID = new dicom_stl::string();
|
|
this->RescaleOffset = 0.0;
|
|
this->RescaleSlope = 1.0;
|
|
this->ImageData = NULL;
|
|
this->ImageDataLengthInBytes = 0;
|
|
this->PatientName = new dicom_stl::string();
|
|
this->StudyUID = new dicom_stl::string();
|
|
this->StudyID = new dicom_stl::string();
|
|
this->GantryAngle = 0.0;
|
|
this->Width = 0;
|
|
this->Height = 0;
|
|
this->PixelRepresentation = 0;
|
|
|
|
this->SeriesUIDCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->SliceNumberCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->SliceLocationCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->ImagePositionPatientCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->ImageOrientationPatientCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->TransferSyntaxCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->ToggleSwapBytesCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->BitsAllocatedCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->PixelSpacingCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->HeightCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->WidthCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->PixelRepresentationCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->PhotometricInterpretationCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->RescaleOffsetCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->RescaleSlopeCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->PixelDataCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->PatientNameCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->StudyUIDCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->StudyIDCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
this->GantryAngleCB = new DICOMMemberCallback<DICOMAppHelper>;
|
|
|
|
this->Implementation = new DICOMAppHelperImplementation;
|
|
}
|
|
|
|
DICOMAppHelper::~DICOMAppHelper()
|
|
{
|
|
this->Clear();
|
|
|
|
this->HeaderFile.close();
|
|
|
|
//
|
|
// Fix warning here.
|
|
//
|
|
if (this->ImageData)
|
|
{
|
|
delete [] (static_cast<char*> (this->ImageData));
|
|
}
|
|
if (this->TransferSyntaxUID)
|
|
{
|
|
delete this->TransferSyntaxUID;
|
|
}
|
|
if (this->PhotometricInterpretation)
|
|
{
|
|
delete this->PhotometricInterpretation;
|
|
}
|
|
|
|
if (this->PatientName)
|
|
{
|
|
delete this->PatientName;
|
|
}
|
|
|
|
if (this->StudyUID)
|
|
{
|
|
delete this->StudyUID;
|
|
}
|
|
|
|
if (this->StudyID)
|
|
{
|
|
delete this->StudyID;
|
|
}
|
|
|
|
delete this->SeriesUIDCB;
|
|
delete this->SliceNumberCB;
|
|
delete this->SliceLocationCB;
|
|
delete this->ImagePositionPatientCB;
|
|
delete this->ImageOrientationPatientCB;
|
|
delete this->TransferSyntaxCB;
|
|
delete this->ToggleSwapBytesCB;
|
|
delete this->BitsAllocatedCB;
|
|
delete this->PixelSpacingCB;
|
|
delete this->HeightCB;
|
|
delete this->WidthCB;
|
|
delete this->PixelRepresentationCB;
|
|
delete this->PhotometricInterpretationCB;
|
|
delete this->RescaleOffsetCB;
|
|
delete this->RescaleSlopeCB;
|
|
delete this->PixelDataCB;
|
|
delete this->PatientNameCB;
|
|
delete this->StudyUIDCB;
|
|
delete this->StudyIDCB;
|
|
delete this->GantryAngleCB;
|
|
|
|
delete this->Implementation;
|
|
}
|
|
|
|
void DICOMAppHelper::RegisterCallbacks(DICOMParser* parser)
|
|
{
|
|
if (!parser)
|
|
{
|
|
dicom_stream::cerr << "Null parser!" << dicom_stream::endl;
|
|
}
|
|
|
|
SeriesUIDCB->SetCallbackFunction(this, &DICOMAppHelper::SeriesUIDCallback);
|
|
parser->AddDICOMTagCallback(0x0020, 0x000e, DICOMParser::VR_UI, SeriesUIDCB);
|
|
|
|
SliceNumberCB->SetCallbackFunction(this, &DICOMAppHelper::SliceNumberCallback);
|
|
parser->AddDICOMTagCallback(0x0020, 0x0013, DICOMParser::VR_IS, SliceNumberCB);
|
|
|
|
SliceLocationCB->SetCallbackFunction(this, &DICOMAppHelper::SliceLocationCallback);
|
|
parser->AddDICOMTagCallback(0x0020, 0x1041, DICOMParser::VR_CS, SliceLocationCB);
|
|
|
|
ImagePositionPatientCB->SetCallbackFunction(this, &DICOMAppHelper::ImagePositionPatientCallback);
|
|
parser->AddDICOMTagCallback(0x0020, 0x0032, DICOMParser::VR_SH, ImagePositionPatientCB);
|
|
|
|
ImageOrientationPatientCB->SetCallbackFunction(this, &DICOMAppHelper::ImageOrientationPatientCallback);
|
|
parser->AddDICOMTagCallback(0x0020, 0x0037, DICOMParser::VR_SH, ImageOrientationPatientCB);
|
|
|
|
TransferSyntaxCB->SetCallbackFunction(this, &DICOMAppHelper::TransferSyntaxCallback);
|
|
parser->AddDICOMTagCallback(0x0002, 0x0010, DICOMParser::VR_UI, TransferSyntaxCB);
|
|
|
|
ToggleSwapBytesCB->SetCallbackFunction(this, &DICOMAppHelper::ToggleSwapBytesCallback);
|
|
|
|
BitsAllocatedCB->SetCallbackFunction(this, &DICOMAppHelper::BitsAllocatedCallback);
|
|
parser->AddDICOMTagCallback(0x0028, 0x0100, DICOMParser::VR_US, BitsAllocatedCB);
|
|
|
|
PixelSpacingCB->SetCallbackFunction(this, &DICOMAppHelper::PixelSpacingCallback);
|
|
parser->AddDICOMTagCallback(0x0028, 0x0030, DICOMParser::VR_FL, PixelSpacingCB);
|
|
parser->AddDICOMTagCallback(0x0018, 0x0050, DICOMParser::VR_FL, PixelSpacingCB);
|
|
|
|
WidthCB->SetCallbackFunction(this, &DICOMAppHelper::WidthCallback);
|
|
parser->AddDICOMTagCallback(0x0028, 0x0011, DICOMParser::VR_US, WidthCB);
|
|
|
|
HeightCB->SetCallbackFunction(this, &DICOMAppHelper::HeightCallback);
|
|
parser->AddDICOMTagCallback(0x0028, 0x0010, DICOMParser::VR_US, HeightCB);
|
|
|
|
PixelRepresentationCB->SetCallbackFunction(this, &DICOMAppHelper::PixelRepresentationCallback);
|
|
parser->AddDICOMTagCallback(0x0028, 0x0103, DICOMParser::VR_US, PixelRepresentationCB);
|
|
|
|
PhotometricInterpretationCB->SetCallbackFunction(this, &DICOMAppHelper::PhotometricInterpretationCallback);
|
|
parser->AddDICOMTagCallback(0x0028, 0x0004, DICOMParser::VR_CS, PhotometricInterpretationCB);
|
|
|
|
RescaleOffsetCB->SetCallbackFunction(this, &DICOMAppHelper::RescaleOffsetCallback);
|
|
parser->AddDICOMTagCallback(0x0028, 0x1052, DICOMParser::VR_CS, RescaleOffsetCB);
|
|
|
|
RescaleSlopeCB->SetCallbackFunction(this, &DICOMAppHelper::RescaleSlopeCallback);
|
|
parser->AddDICOMTagCallback(0x0028, 0x1053, DICOMParser::VR_FL, RescaleSlopeCB);
|
|
|
|
PatientNameCB->SetCallbackFunction(this, &DICOMAppHelper::PatientNameCallback);
|
|
parser->AddDICOMTagCallback(0x0010, 0x0010, DICOMParser::VR_PN, PatientNameCB);
|
|
|
|
StudyUIDCB->SetCallbackFunction(this, &DICOMAppHelper::StudyUIDCallback);
|
|
parser->AddDICOMTagCallback(0x0020, 0x000d, DICOMParser::VR_UI, StudyUIDCB);
|
|
|
|
StudyIDCB->SetCallbackFunction(this, &DICOMAppHelper::StudyIDCallback);
|
|
parser->AddDICOMTagCallback(0x0020, 0x0010, DICOMParser::VR_SH, StudyIDCB);
|
|
|
|
GantryAngleCB->SetCallbackFunction(this, &DICOMAppHelper::GantryAngleCallback);
|
|
parser->AddDICOMTagCallback(0x0018, 0x1120, DICOMParser::VR_FL, GantryAngleCB);
|
|
|
|
|
|
DICOMTagInfo dicom_tags[] = {
|
|
{0x0002, 0x0002, DICOMParser::VR_UI, "Media storage SOP class uid"},
|
|
{0x0002, 0x0003, DICOMParser::VR_UI, "Media storage SOP inst uid"},
|
|
{0x0002, 0x0010, DICOMParser::VR_UI, "Transfer syntax uid"},
|
|
{0x0002, 0x0012, DICOMParser::VR_UI, "Implementation class uid"},
|
|
{0x0008, 0x0018, DICOMParser::VR_UI, "Image UID"},
|
|
{0x0008, 0x0020, DICOMParser::VR_DA, "Series date"},
|
|
{0x0008, 0x0030, DICOMParser::VR_TM, "Series time"},
|
|
{0x0008, 0x0060, DICOMParser::VR_SH, "Modality"},
|
|
{0x0008, 0x0070, DICOMParser::VR_SH, "Manufacturer"},
|
|
{0x0008, 0x1060, DICOMParser::VR_SH, "Physician"},
|
|
{0x0018, 0x0050, DICOMParser::VR_FL, "slice thickness"},
|
|
{0x0018, 0x0060, DICOMParser::VR_FL, "kV"},
|
|
{0x0018, 0x0088, DICOMParser::VR_FL, "slice spacing"},
|
|
{0x0018, 0x1100, DICOMParser::VR_SH, "Recon diameter"},
|
|
{0x0018, 0x1151, DICOMParser::VR_FL, "mA"},
|
|
{0x0018, 0x1210, DICOMParser::VR_SH, "Recon kernel"},
|
|
{0x0020, 0x000d, DICOMParser::VR_UI, "Study UID"},
|
|
{0x0020, 0x000e, DICOMParser::VR_UI, "Series UID"},
|
|
{0x0020, 0x0013, DICOMParser::VR_IS, "Image number"},
|
|
{0x0020, 0x0032, DICOMParser::VR_SH, "Patient position"},
|
|
{0x0020, 0x0037, DICOMParser::VR_SH, "Patient position cosines"},
|
|
{0x0020, 0x1041, DICOMParser::VR_CS, "Slice location"},
|
|
{0x0028, 0x0010, DICOMParser::VR_FL, "Num rows"},
|
|
{0x0028, 0x0011, DICOMParser::VR_FL, "Num cols"},
|
|
{0x0028, 0x0030, DICOMParser::VR_FL, "pixel spacing"},
|
|
{0x0028, 0x0100, DICOMParser::VR_US, "Bits allocated"},
|
|
{0x0028, 0x0120, DICOMParser::VR_UL, "pixel padding"},
|
|
{0x0028, 0x1052, DICOMParser::VR_FL, "pixel offset"}
|
|
};
|
|
|
|
int num_tags = sizeof(dicom_tags)/sizeof(DICOMTagInfo);
|
|
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
DICOMMemberCallback<DICOMAppHelper>** callbackArray = new DICOMMemberCallback<DICOMAppHelper>*[num_tags];
|
|
#endif
|
|
|
|
for (int j = 0; j < num_tags; j++)
|
|
{
|
|
//
|
|
// Setup internal map.
|
|
//
|
|
DICOMTagInfo tagStruct = dicom_tags[j];
|
|
doublebyte group = tagStruct.group;
|
|
doublebyte element = tagStruct.element;
|
|
|
|
dicom_stl::pair<doublebyte, doublebyte> gePair(group, element);
|
|
dicom_stl::pair<const dicom_stl::pair<doublebyte, doublebyte>, DICOMTagInfo> mapPair(gePair, tagStruct);
|
|
this->Implementation->TagMap.insert(mapPair);
|
|
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
//
|
|
// Make callback
|
|
//
|
|
callbackArray[j] = new DICOMMemberCallback<DICOMAppHelper>;
|
|
callbackArray[j]->SetCallbackFunction(this, &DICOMAppHelper::ArrayCallback);
|
|
//
|
|
// Set callback on parser.
|
|
//
|
|
parser->AddDICOMTagCallback(group, element,datatype, callbackArray[j]);
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void DICOMAppHelper::SeriesUIDCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
char* newString = (char*) val;
|
|
dicom_stl::string newStdString(newString);
|
|
dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr>::iterator iter = this->Implementation->SeriesUIDMap.find(newStdString);
|
|
if ( iter == this->Implementation->SeriesUIDMap.end())
|
|
{
|
|
dicom_stl::vector<dicom_stl::string> newVector;
|
|
|
|
newVector.push_back(parser->GetFileName());
|
|
this->Implementation->SeriesUIDMap.insert(dicom_stl::pair<const dicom_stl::string, dicom_stl::vector<dicom_stl::string> > (newStdString, newVector));
|
|
}
|
|
else
|
|
{
|
|
(*iter).second.push_back(parser->GetFileName());
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::OutputSeries()
|
|
{
|
|
dicom_stream::cout << dicom_stream::endl << dicom_stream::endl;
|
|
|
|
for (dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr >::iterator iter = this->Implementation->SeriesUIDMap.begin();
|
|
iter != this->Implementation->SeriesUIDMap.end();
|
|
iter++)
|
|
{
|
|
dicom_stream::cout << "SERIES: " << (*iter).first.c_str() << dicom_stream::endl;
|
|
dicom_stl::vector<dicom_stl::string>& v_ref = (*iter).second;
|
|
|
|
for (dicom_stl::vector<dicom_stl::string>::iterator v_iter = v_ref.begin();
|
|
v_iter != v_ref.end();
|
|
v_iter++)
|
|
{
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator sn_iter = Implementation->SliceOrderingMap.find(*v_iter);
|
|
|
|
int slice = -1;
|
|
if (sn_iter != Implementation->SliceOrderingMap.end())
|
|
{
|
|
slice = (*sn_iter).second.SliceNumber;
|
|
}
|
|
dicom_stream::cout << "\t" << (*v_iter).c_str() << " [" << slice << "]" << dicom_stream::endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::ArrayCallback(DICOMParser *parser,
|
|
doublebyte group,
|
|
doublebyte element,
|
|
DICOMParser::VRTypes datatype,
|
|
unsigned char* val,
|
|
quadbyte len)
|
|
{
|
|
const char* desc = "No description";
|
|
|
|
TagMapType::iterator iter = this->Implementation->TagMap.find(dicom_stl::pair<doublebyte, doublebyte> (group, element));
|
|
if (iter != this->Implementation->TagMap.end())
|
|
{
|
|
desc = (*iter).second.description;
|
|
}
|
|
|
|
int t2 = int((0x0000FF00 & datatype) >> 8);
|
|
int t1 = int((0x000000FF & datatype));
|
|
|
|
char ct2(t2);
|
|
char ct1(t1);
|
|
|
|
|
|
HeaderFile << "(0x";
|
|
|
|
HeaderFile.width(4);
|
|
char prev = HeaderFile.fill('0');
|
|
|
|
HeaderFile << dicom_stream::hex << group;
|
|
HeaderFile << ",0x";
|
|
|
|
HeaderFile.width(4);
|
|
HeaderFile.fill('0');
|
|
|
|
HeaderFile << dicom_stream::hex << element;
|
|
HeaderFile << ") ";
|
|
|
|
HeaderFile.fill(prev);
|
|
HeaderFile << dicom_stream::dec;
|
|
HeaderFile << " " << ct1 << ct2 << " ";
|
|
HeaderFile << "[" << len << " bytes] ";
|
|
|
|
HeaderFile << desc << " : ";
|
|
|
|
unsigned int uival = 0;
|
|
float fval = 0;
|
|
double dval = 0;
|
|
int ival = 0;
|
|
|
|
if (val)
|
|
{
|
|
switch (datatype)
|
|
{
|
|
case DICOMParser::VR_AE:
|
|
case DICOMParser::VR_AS:
|
|
case DICOMParser::VR_CS:
|
|
case DICOMParser::VR_UI:
|
|
case DICOMParser::VR_DA:
|
|
case DICOMParser::VR_DS:
|
|
case DICOMParser::VR_DT:
|
|
case DICOMParser::VR_LO:
|
|
case DICOMParser::VR_LT:
|
|
case DICOMParser::VR_OB: // ordered bytes
|
|
case DICOMParser::VR_OW: // ordered words
|
|
case DICOMParser::VR_PN:
|
|
case DICOMParser::VR_ST:
|
|
case DICOMParser::VR_TM:
|
|
case DICOMParser::VR_UN:
|
|
case DICOMParser::VR_UT:
|
|
case DICOMParser::VR_SQ: // sequence
|
|
case DICOMParser::VR_SH: // strings
|
|
case DICOMParser::VR_IS:
|
|
HeaderFile << val;
|
|
break;
|
|
case DICOMParser::VR_FL: // float
|
|
fval = static_cast<float> (atof((char*) val));
|
|
HeaderFile << fval;
|
|
break;
|
|
case DICOMParser::VR_FD: // float double
|
|
fval = static_cast<float> (atof((char*) val));
|
|
HeaderFile << dval;
|
|
break;
|
|
case DICOMParser::VR_UL: // unsigned long
|
|
case DICOMParser::VR_SL: // signed long
|
|
case DICOMParser::VR_AT:
|
|
HeaderFile << uival;
|
|
break;
|
|
//case DICOMParser::VR_IS:
|
|
// ival = DICOMFile::ReturnAsSignedLong(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
// HeaderFile << ival;
|
|
// break;
|
|
case DICOMParser::VR_SS:
|
|
ival = DICOMFile::ReturnAsSignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
HeaderFile << ival;
|
|
break;
|
|
case DICOMParser::VR_US: // unsigned short
|
|
uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
HeaderFile << uival;
|
|
break;
|
|
default:
|
|
HeaderFile << val << dicom_stream::endl;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HeaderFile << "NULL";
|
|
}
|
|
|
|
HeaderFile << dicom_stream::dec << dicom_stream::endl;
|
|
HeaderFile.fill(prev);
|
|
|
|
delete [] val;
|
|
}
|
|
|
|
void DICOMAppHelper::SliceNumberCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
// Look for the current file in the map of slice ordering data
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator it;
|
|
it = this->Implementation->SliceOrderingMap.find(parser->GetFileName());
|
|
if (it == Implementation->SliceOrderingMap.end())
|
|
{
|
|
// file not found, create a new entry
|
|
DICOMOrderingElements ord;
|
|
ord.SliceNumber = atoi( (char *) val);
|
|
|
|
// insert into the map
|
|
this->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string, DICOMOrderingElements>(parser->GetFileName(), ord));
|
|
}
|
|
else
|
|
{
|
|
// file found, add new values
|
|
(*it).second.SliceNumber = atoi( (char *)val );
|
|
}
|
|
|
|
// cache the slice number
|
|
this->SliceNumber = atoi( (char *) val);
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::SliceLocationCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
// Look for the current file in the map of slice ordering data
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator it;
|
|
it = this->Implementation->SliceOrderingMap.find(parser->GetFileName());
|
|
if (it == Implementation->SliceOrderingMap.end())
|
|
{
|
|
// file not found, create a new entry
|
|
DICOMOrderingElements ord;
|
|
ord.SliceLocation = (float)atof( (char *) val);
|
|
|
|
// insert into the map
|
|
this->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,
|
|
DICOMOrderingElements>(parser->GetFileName(), ord));
|
|
}
|
|
else
|
|
{
|
|
// file found, add new values
|
|
(*it).second.SliceLocation = (float)atof( (char *)val );
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::ImagePositionPatientCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
// Look for the current file in the map of slice ordering data
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator it;
|
|
it = this->Implementation->SliceOrderingMap.find(parser->GetFileName());
|
|
if (it == Implementation->SliceOrderingMap.end())
|
|
{
|
|
// file not found, create a new entry
|
|
DICOMOrderingElements ord;
|
|
|
|
if (val)
|
|
{
|
|
sscanf( (char*)(val), "%f\\%f\\%f",
|
|
&ord.ImagePositionPatient[0],
|
|
&ord.ImagePositionPatient[1],
|
|
&ord.ImagePositionPatient[2] );
|
|
}
|
|
else
|
|
{
|
|
// no actual position specified, default to the origin
|
|
ord.ImagePositionPatient[0] = 0.0;
|
|
ord.ImagePositionPatient[1] = 0.0;
|
|
ord.ImagePositionPatient[2] = 0.0;
|
|
}
|
|
|
|
// insert into the map
|
|
this->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,
|
|
DICOMOrderingElements>(parser->GetFileName(), ord));
|
|
|
|
// cache the value
|
|
memcpy( this->ImagePositionPatient, ord.ImagePositionPatient,
|
|
3*sizeof(float) );
|
|
}
|
|
else
|
|
{
|
|
if (val)
|
|
{
|
|
// file found, add new values
|
|
sscanf( (char*)(val), "%f\\%f\\%f",
|
|
&(*it).second.ImagePositionPatient[0],
|
|
&(*it).second.ImagePositionPatient[1],
|
|
&(*it).second.ImagePositionPatient[2] );
|
|
}
|
|
else
|
|
{
|
|
// no actual position specified, default to the origin
|
|
(*it).second.ImagePositionPatient[0] = 0.0;
|
|
(*it).second.ImagePositionPatient[1] = 0.0;
|
|
(*it).second.ImagePositionPatient[2] = 0.0;
|
|
}
|
|
|
|
// cache the value
|
|
memcpy( this->ImagePositionPatient, (*it).second.ImagePositionPatient,
|
|
3*sizeof(float) );
|
|
}
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::ImageOrientationPatientCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
// Look for the current file in the map of slice ordering data
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator it;
|
|
it = this->Implementation->SliceOrderingMap.find(parser->GetFileName());
|
|
if (it == Implementation->SliceOrderingMap.end())
|
|
{
|
|
// file not found, create a new entry
|
|
DICOMOrderingElements ord;
|
|
if (val)
|
|
{
|
|
sscanf( (char*)(val), "%f\\%f\\%f\\%f\\%f\\%f",
|
|
&ord.ImageOrientationPatient[0],
|
|
&ord.ImageOrientationPatient[1],
|
|
&ord.ImageOrientationPatient[2],
|
|
&ord.ImageOrientationPatient[3],
|
|
&ord.ImageOrientationPatient[4],
|
|
&ord.ImageOrientationPatient[5] );
|
|
}
|
|
else
|
|
{
|
|
// no orientation defined, default to an standard axial orientation
|
|
ord.ImageOrientationPatient[0] = 1.0;
|
|
ord.ImageOrientationPatient[1] = 0.0;
|
|
ord.ImageOrientationPatient[2] = 0.0;
|
|
ord.ImageOrientationPatient[3] = 0.0;
|
|
ord.ImageOrientationPatient[4] = 1.0;
|
|
ord.ImageOrientationPatient[5] = 0.0;
|
|
}
|
|
|
|
// insert into the map
|
|
this->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,
|
|
DICOMOrderingElements>(parser->GetFileName(), ord));
|
|
|
|
// cache the value
|
|
memcpy( this->ImageOrientationPatient, ord.ImageOrientationPatient,
|
|
6*sizeof(float) );
|
|
}
|
|
else
|
|
{
|
|
// file found, add new values
|
|
if (val)
|
|
{
|
|
sscanf( (char*)(val), "%f\\%f\\%f\\%f\\%f\\%f",
|
|
&(*it).second.ImageOrientationPatient[0],
|
|
&(*it).second.ImageOrientationPatient[1],
|
|
&(*it).second.ImageOrientationPatient[2],
|
|
&(*it).second.ImageOrientationPatient[3],
|
|
&(*it).second.ImageOrientationPatient[4],
|
|
&(*it).second.ImageOrientationPatient[5] );
|
|
}
|
|
else
|
|
{
|
|
// no orientation defined, default to an standard axial orientation
|
|
(*it).second.ImageOrientationPatient[0] = 1.0;
|
|
(*it).second.ImageOrientationPatient[1] = 0.0;
|
|
(*it).second.ImageOrientationPatient[2] = 0.0;
|
|
(*it).second.ImageOrientationPatient[3] = 0.0;
|
|
(*it).second.ImageOrientationPatient[4] = 1.0;
|
|
(*it).second.ImageOrientationPatient[5] = 0.0;
|
|
}
|
|
|
|
// cache the value
|
|
memcpy( this->ImageOrientationPatient, (*it).second.ImageOrientationPatient,
|
|
6*sizeof(float) );
|
|
}
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::TransferSyntaxCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
#ifdef WIN32
|
|
char platformByteOrder = 'L';
|
|
#else
|
|
char platformByteOrder = 'B';
|
|
#endif
|
|
dicom_stream::cout << "Platform byte order: " << platformByteOrder << dicom_stream::endl;
|
|
#endif
|
|
|
|
static const char* TRANSFER_UID_EXPLICIT_BIG_ENDIAN = "1.2.840.10008.1.2.2";
|
|
|
|
// Only add the ToggleSwapBytes callback when we need it.
|
|
if (strcmp(TRANSFER_UID_EXPLICIT_BIG_ENDIAN, (char*) val) == 0)
|
|
{
|
|
this->ByteSwapData = true;
|
|
parser->AddDICOMTagCallback(0x0800, 0x0000, DICOMParser::VR_UNKNOWN, ToggleSwapBytesCB);
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cerr <<"Registering callback for swapping bytes." << dicom_stream::endl;
|
|
#endif
|
|
}
|
|
|
|
if (this->TransferSyntaxUID)
|
|
{
|
|
delete this->TransferSyntaxUID;
|
|
}
|
|
this->TransferSyntaxUID = new dicom_stl::string((char*) val);
|
|
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Transfer Syntax UID: " << *this->TransferSyntaxUID;
|
|
dicom_stream::cout << " " << this->TransferSyntaxUIDDescription(this->TransferSyntaxUID->c_str()) << dicom_stream::endl;
|
|
#endif
|
|
}
|
|
|
|
void DICOMAppHelper::BitsAllocatedCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
this->BitsAllocated = parser->GetDICOMFile()->ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Bits allocated: " << this->BitsAllocated << dicom_stream::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::ToggleSwapBytesCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* ,
|
|
quadbyte len)
|
|
{
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "ToggleSwapBytesCallback" << dicom_stream::endl;
|
|
#endif
|
|
bool bs = parser->GetDICOMFile()->GetPlatformIsBigEndian();
|
|
parser->GetDICOMFile()->SetPlatformIsBigEndian(!bs);
|
|
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Set byte swap to: " << parser->GetDICOMFile()->GetPlatformIsBigEndian() << dicom_stream::endl;
|
|
#endif
|
|
|
|
long pos = parser->GetDICOMFile()->Tell();
|
|
|
|
//
|
|
// The +4 is probably a hack, but it's a guess at the length of the previous field.
|
|
//
|
|
parser->GetDICOMFile()->SkipToPos(pos - len + 4);
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::PixelSpacingCallback(DICOMParser *parser,
|
|
doublebyte group,
|
|
doublebyte element,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
float fval = DICOMFile::ReturnAsFloat(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
|
|
if (group == 0x0028 && element == 0x0030)
|
|
{
|
|
this->PixelSpacing[0] = this->PixelSpacing[1] = fval;
|
|
}
|
|
else if (group == 0x0018 && element == 0x0050)
|
|
{
|
|
this->PixelSpacing[2] = fval;
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::WidthCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
unsigned short uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Width: " << uival << dicom_stream::endl;
|
|
#endif
|
|
|
|
this->Width = uival;
|
|
this->Dimensions[0] = this->Width;
|
|
}
|
|
|
|
void DICOMAppHelper::HeightCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
unsigned short uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Height: " << uival << dicom_stream::endl;
|
|
#endif
|
|
this->Height = uival;
|
|
this->Dimensions[1] = this->Height;
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::PixelRepresentationCallback( DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
unsigned short uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Pixel Representation: " << (uival ? "Signed" : "Unsigned") << dicom_stream::endl;
|
|
#endif
|
|
this->PixelRepresentation = uival;
|
|
}
|
|
|
|
void DICOMAppHelper::PhotometricInterpretationCallback( DICOMParser *,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Photometric Interpretation: " << (char*) val << dicom_stream::endl;
|
|
#endif
|
|
if (this->PhotometricInterpretation)
|
|
{
|
|
delete this->PhotometricInterpretation;
|
|
}
|
|
|
|
this->PhotometricInterpretation = new dicom_stl::string((char*) val);
|
|
}
|
|
|
|
void DICOMAppHelper::PixelDataCallback( DICOMParser *,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* data,
|
|
quadbyte len)
|
|
{
|
|
int numPixels = this->Dimensions[0] * this->Dimensions[1] * this->GetNumberOfComponents();
|
|
if (len < numPixels)
|
|
{
|
|
numPixels = len;
|
|
}
|
|
if (numPixels < 0)
|
|
{
|
|
numPixels = 0;
|
|
}
|
|
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "numPixels : " << numPixels << dicom_stream::endl;
|
|
#endif
|
|
|
|
int ptrIncr = int(this->BitsAllocated/8.0);
|
|
|
|
unsigned short* ushortInputData = reinterpret_cast<unsigned short*>(data);
|
|
unsigned char* ucharInputData = data;
|
|
short* shortInputData = reinterpret_cast<short*> (data);
|
|
|
|
float* floatOutputData; // = NULL;
|
|
|
|
bool isFloat = this->RescaledImageDataIsFloat();
|
|
|
|
if (isFloat)
|
|
{
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Slope and offset are not integer valued : ";
|
|
dicom_stream::cout << this->RescaleSlope << ", " << this->RescaleOffset << dicom_stream::endl;
|
|
#endif
|
|
if (this->ImageData)
|
|
{
|
|
delete [] (static_cast<char*> (this->ImageData));
|
|
}
|
|
this->ImageData = new float[numPixels];
|
|
floatOutputData = static_cast<float*> (this->ImageData);
|
|
|
|
this->ImageDataType = DICOMParser::VR_FL;
|
|
this->ImageDataLengthInBytes = numPixels * sizeof(float);
|
|
float newFloatPixel;
|
|
|
|
if (ptrIncr == 1)
|
|
{
|
|
for (int i = 0; i < numPixels; i++)
|
|
{
|
|
newFloatPixel = float(this->RescaleSlope * ucharInputData[i] + this->RescaleOffset);
|
|
floatOutputData[i] = newFloatPixel;
|
|
}
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Did rescale, offset to float from char." << dicom_stream::endl;
|
|
dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl;
|
|
#endif
|
|
}
|
|
else if (ptrIncr == 2)
|
|
{
|
|
for (int i = 0; i < numPixels; i++)
|
|
{
|
|
newFloatPixel = float(this->RescaleSlope * ushortInputData[i] + this->RescaleOffset);
|
|
floatOutputData[i] = newFloatPixel;
|
|
}
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Did rescale, offset to float from short." << dicom_stream::endl;
|
|
dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Slope and offset are integer valued : ";
|
|
dicom_stream::cout << this->RescaleSlope << ", " << this->RescaleOffset << dicom_stream::endl;
|
|
#endif
|
|
|
|
if (ptrIncr == 1)
|
|
{
|
|
if (this->ImageData)
|
|
{
|
|
delete [] (static_cast<char*> (this->ImageData));
|
|
}
|
|
this->ImageData = new char[numPixels];
|
|
|
|
char* charOutputData = static_cast<char*> (this->ImageData);
|
|
|
|
this->ImageDataType = DICOMParser::VR_OB;
|
|
this->ImageDataLengthInBytes = numPixels * sizeof(char);
|
|
char newCharPixel;
|
|
|
|
for (int i = 0; i < numPixels; i++)
|
|
{
|
|
newCharPixel = char(this->RescaleSlope * ucharInputData[i] + this->RescaleOffset);
|
|
charOutputData[i] = newCharPixel;
|
|
}
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Did rescale, offset to char from char." << dicom_stream::endl;
|
|
dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl;
|
|
#endif
|
|
}
|
|
else if (ptrIncr == 2)
|
|
{
|
|
if (this->ImageData)
|
|
{
|
|
delete [] (static_cast<char*> (this->ImageData));
|
|
}
|
|
this->ImageData = new short[numPixels];
|
|
short* shortOutputData = static_cast<short*> (this->ImageData);
|
|
|
|
this->ImageDataType = DICOMParser::VR_OW;
|
|
this->ImageDataLengthInBytes = numPixels * sizeof(short);
|
|
short newShortPixel;
|
|
for (int i = 0; i < numPixels; i++)
|
|
{
|
|
newShortPixel = short(this->RescaleSlope * shortInputData[i] + this->RescaleOffset);
|
|
shortOutputData[i] = newShortPixel;
|
|
}
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Did rescale, offset to short from short." << dicom_stream::endl;
|
|
dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::RegisterPixelDataCallback(DICOMParser* parser)
|
|
{
|
|
this->PixelDataCB->SetCallbackFunction(this, &DICOMAppHelper::PixelDataCallback);
|
|
parser->AddDICOMTagCallback(0x7FE0, 0x0010, DICOMParser::VR_OW, this->PixelDataCB);
|
|
}
|
|
|
|
void DICOMAppHelper::RescaleOffsetCallback( DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
float fval = DICOMFile::ReturnAsFloat(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
|
|
this->RescaleOffset = fval;
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Pixel offset: " << this->RescaleOffset << dicom_stream::endl;
|
|
#endif
|
|
}
|
|
|
|
const char* DICOMAppHelper::TransferSyntaxUIDDescription(const char* uid)
|
|
{
|
|
static const char* DICOM_IMPLICIT_VR_LITTLE_ENDIAN = "1.2.840.10008.1.2";
|
|
static const char* DICOM_LOSSLESS_JPEG = "1.2.840.10008.1.2.4.70";
|
|
static const char* DICOM_LOSSY_JPEG_8BIT = "1.2.840.10008.1.2.4.50";
|
|
static const char* DICOM_LOSSY_JPEG_16BIT = "1.2.840.10008.1.2.4.51";
|
|
static const char* DICOM_EXPLICIT_VR_LITTLE_ENDIAN = "1.2.840.10008.1.2.1";
|
|
static const char* DICOM_EXPLICIT_VR_BIG_ENDIAN = "1.2.840.10008.1.2.2";
|
|
static const char* DICOM_GE_PRIVATE_IMPLICIT_BIG_ENDIAN = "1.2.840.113619.5.2";
|
|
|
|
if (!strcmp(DICOM_IMPLICIT_VR_LITTLE_ENDIAN, uid))
|
|
{
|
|
return "Implicit VR, Little Endian";
|
|
}
|
|
else if (!strcmp(DICOM_LOSSLESS_JPEG, uid))
|
|
{
|
|
return "Lossless JPEG";
|
|
}
|
|
else if (!strcmp(DICOM_LOSSY_JPEG_8BIT, uid))
|
|
{
|
|
return "Lossy JPEG 8 bit";
|
|
}
|
|
else if (!strcmp(DICOM_LOSSY_JPEG_16BIT, uid))
|
|
{
|
|
return "Lossy JPEG 16 bit.";
|
|
}
|
|
else if (!strcmp(DICOM_EXPLICIT_VR_LITTLE_ENDIAN, uid))
|
|
{
|
|
return "Explicit VR, Little Endian.";
|
|
}
|
|
else if (!strcmp(DICOM_EXPLICIT_VR_BIG_ENDIAN, uid))
|
|
{
|
|
return "Explicit VR, Big Endian.";
|
|
}
|
|
else if (!strcmp(DICOM_GE_PRIVATE_IMPLICIT_BIG_ENDIAN, uid))
|
|
{
|
|
return "GE Private, Implicit VR, Big Endian Image Data.";
|
|
}
|
|
else
|
|
{
|
|
return "Unknown.";
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::RescaleSlopeCallback(DICOMParser *parser,
|
|
doublebyte,
|
|
doublebyte ,
|
|
DICOMParser::VRTypes ,
|
|
unsigned char* val,
|
|
quadbyte )
|
|
{
|
|
float fval = DICOMFile::ReturnAsFloat(val,
|
|
parser->GetDICOMFile()->GetPlatformIsBigEndian ());
|
|
#ifdef DEBUG_DICOM_APP_HELPER
|
|
dicom_stream::cout << "Rescale slope: " << fval << dicom_stream::endl;
|
|
#endif
|
|
this->RescaleSlope = fval;
|
|
}
|
|
|
|
bool DICOMAppHelper::RescaledImageDataIsFloat()
|
|
{
|
|
int s = int(this->RescaleSlope);
|
|
int o = int(this->RescaleOffset);
|
|
|
|
float sf = float(s);
|
|
float of = float(o);
|
|
|
|
double d1 = fabs(sf - this->RescaleSlope);
|
|
double d2 = fabs(of - this->RescaleOffset);
|
|
|
|
if (d1 > 0.0 || d2 > 0.0)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::GetImageData(void*& data, DICOMParser::VRTypes& dataType, unsigned long& len)
|
|
{
|
|
data = this->ImageData;
|
|
dataType = this->ImageDataType;
|
|
len = this->ImageDataLengthInBytes;
|
|
}
|
|
|
|
bool DICOMAppHelper::RescaledImageDataIsSigned()
|
|
{
|
|
bool rescaleSigned = (this->RescaleSlope < 0.0);
|
|
bool pixelRepSigned = (this->PixelRepresentation == 1);
|
|
bool offsetSigned = (this->RescaleOffset < 0.0);
|
|
|
|
return (rescaleSigned || pixelRepSigned || offsetSigned);
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::GetSliceNumberFilenamePairs(const dicom_stl::string &seriesUID,
|
|
dicom_stl::vector<dicom_stl::pair<int, dicom_stl::string> >& v, bool ascending)
|
|
{
|
|
v.clear();
|
|
|
|
dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr >::iterator miter = this->Implementation->SeriesUIDMap.find(seriesUID);
|
|
|
|
if (miter == this->Implementation->SeriesUIDMap.end() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// grab the filenames for the specified series
|
|
dicom_stl::vector<dicom_stl::string> files = (*miter).second;
|
|
|
|
for (dicom_stl::vector<dicom_stl::string>::iterator fileIter = files.begin();
|
|
fileIter != files.end();
|
|
fileIter++)
|
|
{
|
|
dicom_stl::pair<int, dicom_stl::string> p;
|
|
p.second = dicom_stl::string(*fileIter);
|
|
int slice_number;
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator sn_iter = Implementation->SliceOrderingMap.find(*fileIter);
|
|
// Only store files that have a valid slice number
|
|
if (sn_iter != Implementation->SliceOrderingMap.end())
|
|
{
|
|
slice_number = (*sn_iter).second.SliceNumber;
|
|
p.first = slice_number;
|
|
v.push_back(p);
|
|
}
|
|
}
|
|
if (ascending)
|
|
{
|
|
dicom_stl::sort(v.begin(), v.end(), lt_pair_int_string());
|
|
}
|
|
else
|
|
{
|
|
dicom_stl::sort(v.begin(), v.end(), gt_pair_int_string());
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::GetSliceNumberFilenamePairs(dicom_stl::vector<dicom_stl::pair<int, dicom_stl::string> >& v, bool ascending)
|
|
{
|
|
// Default to using the first series
|
|
if (this->Implementation->SeriesUIDMap.size() > 0)
|
|
{
|
|
this->GetSliceNumberFilenamePairs( (*this->Implementation->SeriesUIDMap.begin()).first, v, ascending );
|
|
}
|
|
else
|
|
{
|
|
v.clear();
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::GetSliceLocationFilenamePairs(const dicom_stl::string &seriesUID,
|
|
dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> >& v, bool ascending)
|
|
{
|
|
v.clear();
|
|
|
|
dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr >::iterator miter = this->Implementation->SeriesUIDMap.find(seriesUID);
|
|
|
|
if (miter == this->Implementation->SeriesUIDMap.end() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// grab the filenames for the specified series
|
|
dicom_stl::vector<dicom_stl::string> files = (*miter).second;
|
|
|
|
for (dicom_stl::vector<dicom_stl::string>::iterator fileIter = files.begin();
|
|
fileIter != files.end();
|
|
fileIter++)
|
|
{
|
|
dicom_stl::pair<float, dicom_stl::string> p;
|
|
p.second = dicom_stl::string(*fileIter);
|
|
float slice_location;
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator sn_iter = Implementation->SliceOrderingMap.find(*fileIter);
|
|
|
|
if (sn_iter != Implementation->SliceOrderingMap.end())
|
|
{
|
|
slice_location = (*sn_iter).second.SliceLocation;
|
|
p.first = slice_location;
|
|
v.push_back(p);
|
|
}
|
|
}
|
|
if (ascending)
|
|
{
|
|
dicom_stl::sort(v.begin(), v.end(), lt_pair_float_string());
|
|
}
|
|
else
|
|
{
|
|
dicom_stl::sort(v.begin(), v.end(), gt_pair_float_string());
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::GetSliceLocationFilenamePairs(dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> >& v, bool ascending)
|
|
{
|
|
// Default to using the first series
|
|
if (this->Implementation->SeriesUIDMap.size() > 0)
|
|
{
|
|
this->GetSliceLocationFilenamePairs( (*this->Implementation->SeriesUIDMap.begin()).first,
|
|
v , ascending);
|
|
}
|
|
else
|
|
{
|
|
v.clear();
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::GetImagePositionPatientFilenamePairs(const dicom_stl::string &seriesUID, dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> >& v, bool ascending)
|
|
{
|
|
v.clear();
|
|
|
|
dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr >::iterator miter = this->Implementation->SeriesUIDMap.find(seriesUID);
|
|
|
|
if (miter == this->Implementation->SeriesUIDMap.end() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// grab the filenames for the specified series
|
|
dicom_stl::vector<dicom_stl::string> files = (*miter).second;
|
|
|
|
for (dicom_stl::vector<dicom_stl::string>::iterator fileIter = files.begin();
|
|
fileIter != files.end();
|
|
fileIter++)
|
|
{
|
|
dicom_stl::pair<float, dicom_stl::string> p;
|
|
p.second = dicom_stl::string(*fileIter);
|
|
|
|
float image_position;
|
|
float normal[3];
|
|
|
|
dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator sn_iter =
|
|
Implementation->SliceOrderingMap.find(*fileIter);
|
|
|
|
if (sn_iter != Implementation->SliceOrderingMap.end())
|
|
{
|
|
// compute the image patient position wrt to the slice image
|
|
// plane normal
|
|
|
|
normal[0] = ((*sn_iter).second.ImageOrientationPatient[1]
|
|
* (*sn_iter).second.ImageOrientationPatient[5])
|
|
- ((*sn_iter).second.ImageOrientationPatient[2]
|
|
* (*sn_iter).second.ImageOrientationPatient[4]);
|
|
normal[1] = ((*sn_iter).second.ImageOrientationPatient[0]
|
|
*(*sn_iter).second.ImageOrientationPatient[5])
|
|
- ((*sn_iter).second.ImageOrientationPatient[2]
|
|
* (*sn_iter).second.ImageOrientationPatient[3]);
|
|
normal[2] = ((*sn_iter).second.ImageOrientationPatient[0]
|
|
* (*sn_iter).second.ImageOrientationPatient[4])
|
|
- ((*sn_iter).second.ImageOrientationPatient[1]
|
|
* (*sn_iter).second.ImageOrientationPatient[3]);
|
|
|
|
image_position = (normal[0]*(*sn_iter).second.ImagePositionPatient[0])
|
|
+ (normal[1]*(*sn_iter).second.ImagePositionPatient[1])
|
|
+ (normal[2]*(*sn_iter).second.ImagePositionPatient[2]);
|
|
p.first = image_position;
|
|
v.push_back(p);
|
|
}
|
|
}
|
|
if (ascending)
|
|
{
|
|
dicom_stl::sort(v.begin(), v.end(), lt_pair_float_string());
|
|
}
|
|
else
|
|
{
|
|
dicom_stl::sort(v.begin(), v.end(), gt_pair_float_string());
|
|
}
|
|
}
|
|
|
|
|
|
void DICOMAppHelper::GetImagePositionPatientFilenamePairs(dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> >& v, bool ascending)
|
|
{
|
|
// Default to using the first series
|
|
if (this->Implementation->SeriesUIDMap.size() > 0)
|
|
{
|
|
this->GetImagePositionPatientFilenamePairs(
|
|
(*this->Implementation->SeriesUIDMap.begin()).first, v, ascending);
|
|
}
|
|
else
|
|
{
|
|
v.clear();
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::GetSeriesUIDs(dicom_stl::vector<dicom_stl::string> &v)
|
|
{
|
|
v.clear();
|
|
|
|
dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr >::iterator miter;
|
|
|
|
for (miter = this->Implementation->SeriesUIDMap.begin(); miter != this->Implementation->SeriesUIDMap.end();
|
|
++miter)
|
|
{
|
|
v.push_back( (*miter).first );
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::Clear()
|
|
{
|
|
this->Implementation->SliceOrderingMap.clear();
|
|
this->Implementation->SeriesUIDMap.clear();
|
|
}
|
|
|
|
void DICOMAppHelper::PatientNameCallback(DICOMParser *,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
if (this->PatientName)
|
|
{
|
|
delete this->PatientName;
|
|
}
|
|
|
|
if (val)
|
|
{
|
|
this->PatientName = new dicom_stl::string((char*) val);
|
|
}
|
|
else
|
|
{
|
|
this->PatientName = new dicom_stl::string();
|
|
}
|
|
}
|
|
|
|
void DICOMAppHelper::StudyUIDCallback(DICOMParser *,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
if (this->StudyUID)
|
|
{
|
|
delete this->StudyUID;
|
|
}
|
|
|
|
this->StudyUID = new dicom_stl::string((char*) val);
|
|
|
|
}
|
|
|
|
void DICOMAppHelper::StudyIDCallback(DICOMParser *,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
if (this->StudyID)
|
|
{
|
|
delete this->StudyID;
|
|
}
|
|
|
|
if (val)
|
|
{
|
|
this->StudyID = new dicom_stl::string((char*) val);
|
|
}
|
|
else
|
|
{
|
|
this->StudyID = new dicom_stl::string();
|
|
}
|
|
|
|
}
|
|
|
|
void DICOMAppHelper::GantryAngleCallback(DICOMParser * parser,
|
|
doublebyte,
|
|
doublebyte,
|
|
DICOMParser::VRTypes,
|
|
unsigned char* val,
|
|
quadbyte)
|
|
{
|
|
float fval = DICOMFile::ReturnAsFloat(val,
|
|
parser->GetDICOMFile()->GetPlatformIsBigEndian ());
|
|
|
|
this->GantryAngle = fval;
|
|
}
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning ( pop )
|
|
#endif
|
|
|
|
|