GDCM  2.4.5
DumpPhilipsECHO.cxx
/*=========================================================================
Program: GDCM (Grassroots DICOM). A DICOM library
Copyright (c) 2006-2011 Mathieu Malaterre
All rights reserved.
See Copyright.txt or http://gdcm.sourceforge.net/Copyright.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 notice for more information.
=========================================================================*/
#include "gdcmReader.h"
#include "gdcm_zlib.h"
/*
* This example extract the ZLIB compressed US image from a Philips private tag
*
* Everything done in this code is for the sole purpose of writing interoperable
* software under Sect. 1201 (f) Reverse Engineering exception of the DMCA.
* If you believe anything in this code violates any law or any of your rights,
* please contact us (gdcm-developers@lists.sourceforge.net) so that we can
* find a solution.
*
* Everything you do with this code is at your own risk, since decompression
* algorithm was not written from specification documents.
*
* Usage:
*
* $ DumpPhilipsECHO private_us.dcm raw_us_img.raw
* $ gdcmimg --sop-class-uid 1.2.840.10008.5.1.4.1.1.3.1 --size 608,427,88 raw_us_img.raw raw_us_img.dcm
*/
// header:
struct hframe
{
uint32_t val0; // 800 increment ?
uint16_t val1[2];
uint16_t val2[2];
uint32_t imgsize;
bool operator==(const hframe &h) const
{
return val0 == h.val0 &&
val1[0] == h.val1[0] &&
val1[1] == h.val1[1] &&
val2[0] == h.val2[0] &&
val2[1] == h.val2[1] &&
imgsize == h.imgsize;
}
};
static bool ProcessDeflate( const char *outfilename, const int nslices, const
int buf_size, const char *buf, const std::streampos len,
const char *crcbuf, const size_t crclen )
{
std::vector< hframe > crcheaders;
crcheaders.reserve( nslices );
{
std::istringstream is;
is.str( std::string( crcbuf, crclen ) );
hframe header;
for( int r = 0; r < nslices; ++r )
{
is.read( (char*)&header, sizeof( header ));
#if 0
std::cout << header.val0
<< " " << header.val1[0]
<< " " << header.val1[1]
<< " " << header.val2[0]
<< " " << header.val2[1]
<< " " << header.imgsize << std::endl;
#endif
crcheaders.push_back( header );
}
}
std::istringstream is;
is.str( std::string( buf, len ) );
std::streamoff totalsize;
is.read( (char*)&totalsize, sizeof( totalsize ));
assert( totalsize == len );
uint32_t nframes;
is.read( (char*)&nframes, sizeof( nframes ));
assert( nframes == (uint32_t)nslices );
std::vector< std::streamoff > offsets;
offsets.reserve( nframes );
for( uint32_t frame = 0; frame < nframes ; ++frame )
{
uint32_t offset;
is.read( (char*)&offset, sizeof( offset ));
offsets.push_back( offset );
}
std::vector<char> outbuf;
const int size[2] = { 608, 427 }; // FIXME: where does it comes from ?
std::stringstream ss;
ss << outfilename;
ss << '_';
//ss << crcheaders[0].imgsize; // FIXME: Assume all header are identical !
ss << size[0];
ss << '_';
ss << size[1];
ss << '_';
ss << nframes;
ss << ".raw";
std::ofstream os( ss.str().c_str(), std::ios::binary );
assert( buf_size >= size[0] * size[1] );
outbuf.resize( buf_size );
hframe header;
//uint32_t prev = 0;
for( unsigned int r = 0; r < nframes; ++r )
{
is.read( (char*)&header, sizeof( header ));
assert( header == crcheaders[r] );
assert( header.val1[0] == 2000 );
assert( header.val1[1] == 3 );
assert( header.val2[0] == 1 );
assert( header.val2[1] == 1280 );
uLongf destLen = buf_size; // >= 608,427
Bytef *dest = (Bytef*)&outbuf[0];
assert( is.tellg() == offsets[r] + 16 );
const Bytef *source = (Bytef*)buf + offsets[r] + 16;
uLong sourceLen;
if( r + 1 == nframes )
sourceLen = totalsize - offsets[r] - 16;
else
sourceLen = offsets[r+1] - offsets[r] - 16;
// FIXME: in-memory decompression:
int ret = uncompress (dest, &destLen, source, sourceLen);
assert( ret == Z_OK ); (void)ret;
assert( destLen >= (uLongf)size[0] * size[1] ); // 16bytes padding ?
assert( header.imgsize == (uint32_t)size[0] * size[1] );
//os.write( &outbuf[0], outbuf.size() );
os.write( &outbuf[0], size[0] * size[1] );
// skip data:
is.seekg( sourceLen, std::ios::cur );
}
os.close();
assert( is.tellg() == totalsize );
return true;
}
static bool ProcessNone( const char *outfilename, const int nslices, const
int buf_size, const char *buf, const std::streampos len,
const char *crcbuf, const size_t crclen )
{
std::vector< hframe > crcheaders;
crcheaders.reserve( nslices );
{
std::istringstream is;
is.str( std::string( crcbuf, crclen ) );
hframe header;
for( int r = 0; r < nslices; ++r )
{
is.read( (char*)&header, sizeof( header ));
#if 0
std::cout << header.val0
<< " " << header.val1[0]
<< " " << header.val1[1]
<< " " << header.val2[0]
<< " " << header.val2[1]
<< " " << header.imgsize << std::endl;
#endif
crcheaders.push_back( header );
}
}
std::istringstream is;
is.str( std::string( buf, len ) );
std::streampos totalsize;
is.read( (char*)&totalsize, sizeof( totalsize ));
assert( totalsize == len );
uint32_t nframes;
is.read( (char*)&nframes, sizeof( nframes ));
assert( nframes == (uint32_t)nslices );
std::vector< uint32_t > offsets;
offsets.reserve( nframes );
for( uint32_t frame = 0; frame < nframes ; ++frame )
{
uint32_t offset;
is.read( (char*)&offset, sizeof( offset ));
offsets.push_back( offset );
//std::cout << offset << std::endl;
}
std::vector<char> outbuf;
// No idea how to present the data, I'll just append everything, and present it as 2D
std::stringstream ss;
ss << outfilename;
ss << '_';
ss << crcheaders[0].imgsize; // FIXME: Assume all header are identical !
ss << '_';
ss << nframes;
ss << ".raw";
std::ofstream os( ss.str().c_str(), std::ios::binary );
outbuf.resize( buf_size ); // overallocated + 16
char *buffer = &outbuf[0];
hframe header;
for( unsigned int r = 0; r < nframes; ++r )
{
is.read( (char*)&header, sizeof( header ));
#if 0
std::cout << header.val0
<< " " << header.val1[0]
<< " " << header.val1[1]
<< " " << header.val2[0]
<< " " << header.val2[1]
<< " " << header.imgsize << std::endl;
#endif
assert( header == crcheaders[r] );
is.read( buffer, buf_size - 16 );
os.write( buffer, header.imgsize );
}
assert( is.tellg() == totalsize );
os.close();
return true;
}
#ifndef NDEBUG
static const char * const UDM_USD_DATATYPE_STRINGS[] = {
"UDM_USD_DATATYPE_DIN_2D_ECHO",
"UDM_USD_DATATYPE_DIN_2D_ECHO_CONTRAST",
"UDM_USD_DATATYPE_DIN_DOPPLER_CW",
"UDM_USD_DATATYPE_DIN_DOPPLER_PW",
"UDM_USD_DATATYPE_DIN_DOPPLER_PW_TDI",
"UDM_USD_DATATYPE_DIN_2D_COLOR_FLOW",
"UDM_USD_DATATYPE_DIN_2D_COLOR_PMI",
"UDM_USD_DATATYPE_DIN_2D_COLOR_CPA",
"UDM_USD_DATATYPE_DIN_2D_COLOR_TDI",
"UDM_USD_DATATYPE_DIN_MMODE_ECHO",
"UDM_USD_DATATYPE_DIN_MMODE_COLOR",
"UDM_USD_DATATYPE_DIN_MMODE_COLOR_TDI",
"UDM_USD_DATATYPE_DIN_PARAM_BLOCK",
"UDM_USD_DATATYPE_DIN_2D_COLOR_VELOCITY",
"UDM_USD_DATATYPE_DIN_2D_COLOR_POWER",
"UDM_USD_DATATYPE_DIN_2D_COLOR_VARIANCE",
"UDM_USD_DATATYPE_DIN_DOPPLER_AUDIO",
"UDM_USD_DATATYPE_DIN_DOPPLER_HIGHQ",
"UDM_USD_DATATYPE_DIN_PHYSIO",
"UDM_USD_DATATYPE_DIN_2D_COLOR_STRAIN",
"UDM_USD_DATATYPE_DIN_COMPOSITE_RGB",
"UDM_USD_DATATYPE_DIN_XFOV_REALTIME_GRAPHICS",
"UDM_USD_DATATYPE_DIN_XFOV_MOSAIC",
"UDM_USD_DATATYPE_DIN_COMPOSITE_R",
"UDM_USD_DATATYPE_DIN_COMPOSITE_G",
"UDM_USD_DATATYPE_DIN_COMPOSITE_B",
"UDM_USD_DATATYPE_DIN_MMODE_COLOR_VELOCITY",
"UDM_USD_DATATYPE_DIN_MMODE_COLOR_POWER",
"UDM_USD_DATATYPE_DIN_MMODE_COLOR_VARIANCE",
"UDM_USD_DATATYPE_DIN_2D_ELASTO",
};
static inline bool is_valid( const char * datatype_str )
{
static const int n = sizeof( UDM_USD_DATATYPE_STRINGS ) / sizeof( *UDM_USD_DATATYPE_STRINGS );
bool found = false;
if( datatype_str )
{
for( int i = 0; !found && i < n; ++i )
{
found = strcmp( datatype_str, UDM_USD_DATATYPE_STRINGS[i] ) == 0;
}
}
return found;
}
#endif
int main(int argc, char *argv[])
{
if( argc < 2 ) return 1;
using namespace gdcm;
const char *filename = argv[1];
gdcm::Reader reader;
reader.SetFileName( filename );
if( !reader.Read() ) return 1;
gdcm::File &file = reader.GetFile();
gdcm::DataSet &ds1 = file.GetDataSet();
const PrivateTag tseq1(0x200d,0x3cf8,"Philips US Imaging DD 045");
if( !ds1.FindDataElement( tseq1 ) ) return 1;
const DataElement& seq1 = ds1.GetDataElement( tseq1 );
assert( sqi1->GetNumberOfItems() >= 1 );
const size_t nitems = sqi1->GetNumberOfItems();
for( size_t item = 1; item < nitems; ++item )
{
Item &item1 = sqi1->GetItem(item);
DataSet &ds2 = item1.GetNestedDataSet();
// (200d,300d) LO 28 UDM_USD_DATATYPE_DIN_2D_ECHO
const PrivateTag tdatatype(0x200d,0x300d,"Philips US Imaging DD 033");
if( !ds2.FindDataElement( tdatatype ) ) return 1;
const DataElement& datatype = ds2.GetDataElement( tdatatype );
const ByteValue *bvdatatype = datatype.GetByteValue();
if( !bvdatatype ) return 1;
const PrivateTag tseq2(0x200d,0x3cf1,"Philips US Imaging DD 045");
if( !ds2.FindDataElement( tseq2 ) ) return 1;
const DataElement& seq2 = ds2.GetDataElement( tseq2 );
assert( sqi2->GetNumberOfItems() >= 1 );
// FIXME: what if not in first Item ?
assert( sqi2->GetNumberOfItems() == 1 );
Item &item2 = sqi2->GetItem(1);
DataSet &ds3 = item2.GetNestedDataSet();
const PrivateTag tzlib(0x200d,0x3cfa,"Philips US Imaging DD 045");
if( !ds3.FindDataElement( tzlib ) ) return 1;
const DataElement& zlib = ds3.GetDataElement( tzlib );
const ByteValue *bv = zlib.GetByteValue();
if( !bv ) return 1;
if( bv->GetLength() != 4 ) return 1;
// (200d,3010) IS 2 88
const PrivateTag tnslices(0x200d,0x3010,"Philips US Imaging DD 033");
if( !ds3.FindDataElement( tnslices ) ) return 1;
const DataElement& nslices = ds3.GetDataElement( tnslices );
elnslices.SetFromDataElement( nslices );
const int nslicesref = elnslices.GetValue();
assert( nslicesref >= 0 );
// (200d,3011) IS 6 259648
const PrivateTag tzalloc(0x200d,0x3011,"Philips US Imaging DD 033");
if( !ds3.FindDataElement( tzalloc ) ) return 1;
const DataElement& zalloc = ds3.GetDataElement( tzalloc );
elzalloc.SetFromDataElement( zalloc );
const int zallocref = elzalloc.GetValue();
assert( zallocref >= 0 );
// (200d,3021) IS 2 0
const PrivateTag tzero(0x200d,0x3021,"Philips US Imaging DD 033");
if( !ds3.FindDataElement( tzero ) ) return 1;
const DataElement& zero = ds3.GetDataElement( tzero );
elzero.SetFromDataElement( zero );
const int zerocref = elzero.GetValue();
assert( zerocref == 0 ); (void)zerocref;
// (200d,3cf3) OB
const PrivateTag tdeflate(0x200d,0x3cf3,"Philips US Imaging DD 045");
if( !ds3.FindDataElement( tdeflate) ) return 1;
const DataElement& deflate = ds3.GetDataElement( tdeflate );
const ByteValue *bv2 = deflate.GetByteValue();
// (200d,3cfb) OB
const PrivateTag tcrc(0x200d,0x3cfb,"Philips US Imaging DD 045");
if( !ds3.FindDataElement( tcrc ) ) return 1;
const DataElement& crc = ds3.GetDataElement( tcrc );
const ByteValue *bv3 = crc.GetByteValue();
std::string outfile = std::string( bvdatatype->GetPointer(), bvdatatype->GetLength() );
outfile = LOComp::Trim( outfile.c_str() );
const char *outfilename = outfile.c_str();
assert( is_valid(outfilename) );
if( bv2 )
{
assert( bv3 );
assert( zallocref > 0 );
assert( nslicesref > 0 );
std::cout << ds2 << std::endl;
if( strncmp(bv->GetPointer(), "ZLib", 4) == 0 )
{
if( !ProcessDeflate( outfilename, nslicesref, zallocref, bv2->GetPointer(),
std::streampos(bv2->GetLength()), bv3->GetPointer(), bv3->GetLength() ) )
{
return 1;
}
}
else if( strncmp(bv->GetPointer(), "None", 4) == 0 )
{
if( !ProcessNone( outfilename, nslicesref, zallocref, bv2->GetPointer(),
std::streampos(bv2->GetLength()), bv3->GetPointer(), bv3->GetLength() ) )
{
return 1;
}
}
else
{
std::string str( bv->GetPointer(), bv->GetLength() );
std::cerr << "Unhandled: " << str << std::endl;
return 1;
}
}
}
return 0;
}

Generated on Fri Sep 25 2015 17:58:19 for GDCM by doxygen 1.8.9.1
SourceForge.net Logo