#include "gdcmImageCodec.h"
#include "gdcmJPEGCodec.h"
#include "gdcmByteSwap.txx"
#include "gdcmImageChangePhotometricInterpretation.h"
#include "gdcmTrace.h"
#include <iostream>
#include <iomanip>
#include <iterator>
#include <climits>
#include <cstring>
namespace gdcm
{
class ImageInternals
{
public:
};
ImageCodec::ImageCodec()
{
PlanarConfiguration = 0;
RequestPlanarConfiguration = false;
RequestPaddedCompositePixelCode = false;
PI = PhotometricInterpretation::UNKNOWN;
LUT = new LookupTable;
NeedByteSwap = false;
NeedOverlayCleanup = false;
Dimensions[0] = Dimensions[1] = Dimensions[2] = 0;
NumberOfDimensions = 0;
LossyFlag = false;
}
ImageCodec::~ImageCodec()
= default;
bool ImageCodec::GetHeaderInfo(std::istream &, TransferSyntax &)
{
gdcm_assert( 0 );
return false;
}
void ImageCodec::SetLossyFlag(bool l)
{
LossyFlag = l;
}
bool ImageCodec::GetLossyFlag() const
{
return LossyFlag;
}
bool ImageCodec::IsLossy() const
{
return LossyFlag;
}
void ImageCodec::SetNumberOfDimensions(unsigned int dim)
{
NumberOfDimensions = dim;
}
unsigned int ImageCodec::GetNumberOfDimensions() const
{
return NumberOfDimensions;
}
const PhotometricInterpretation &ImageCodec::GetPhotometricInterpretation() const
{
return PI;
}
void ImageCodec::SetPhotometricInterpretation(
PhotometricInterpretation const &pi)
{
PI = pi;
}
bool ImageCodec::DoByteSwap(std::istream &is, std::ostream &os)
{
std::streampos start = is.tellg();
gdcm_assert( 0 - start == 0 );
is.seekg( 0, std::ios::end);
size_t buf_size = (size_t)is.tellg();
char *dummy_buffer = new char[(unsigned int)buf_size];
is.seekg(start, std::ios::beg);
is.read( dummy_buffer, buf_size);
is.seekg(start, std::ios::beg);
gdcm_assert( !(buf_size % 2) );
#ifdef GDCM_WORDS_BIGENDIAN
if( PF.GetBitsAllocated() == 16 )
{
ByteSwap<uint16_t>::SwapRangeFromSwapCodeIntoSystem((uint16_t*)
(void*)dummy_buffer, SwapCode::LittleEndian, buf_size/2);
}
#else
if ( PF.GetBitsAllocated() == 16 )
{
ByteSwap<uint16_t>::SwapRangeFromSwapCodeIntoSystem((uint16_t*)
(void*)dummy_buffer, SwapCode::BigEndian, buf_size/2);
}
#endif
os.write(dummy_buffer, buf_size);
delete[] dummy_buffer;
return true;
}
bool ImageCodec::DoYBR(std::istream &is, std::ostream &os)
{
std::streampos start = is.tellg();
gdcm_assert( 0 - start == 0 );
is.seekg( 0, std::ios::end);
size_t buf_size = (size_t)is.tellg();
char *dummy_buffer = new char[(unsigned int)buf_size];
is.seekg(start, std::ios::beg);
is.read( dummy_buffer, buf_size);
is.seekg(start, std::ios::beg);
gdcm_assert( !(buf_size % 3) );
unsigned long size = (unsigned long)buf_size/3;
unsigned char *copy = new unsigned char[ (unsigned int)buf_size ];
memmove( copy, dummy_buffer, (size_t)buf_size);
gdcm_assert(0); const unsigned char *a = copy + 0;
const unsigned char *b = copy + size;
const unsigned char *c = copy + size + size;
unsigned char *p = (unsigned char*)dummy_buffer;
for (unsigned long j = 0; j < size; ++j)
{
int R = 38142 *(*a-16) + 52298 *(*c -128);
int G = 38142 *(*a-16) - 26640 *(*c -128) - 12845 *(*b -128);
int B = 38142 *(*a-16) + 66093 *(*b -128);
R = (R+16384)>>15;
G = (G+16384)>>15;
B = (B+16384)>>15;
if (R < 0) R = 0;
if (G < 0) G = 0;
if (B < 0) B = 0;
if (R > 255) R = 255;
if (G > 255) G = 255;
if (B > 255) B = 255;
*(p++) = (unsigned char)R;
*(p++) = (unsigned char)G;
*(p++) = (unsigned char)B;
a++;
b++;
c++;
}
delete[] copy;
os.write(dummy_buffer, buf_size);
delete[] dummy_buffer;
return true;
}
bool ImageCodec::DoYBRFull422(std::istream &is, std::ostream &os)
{
std::streampos start = is.tellg();
gdcm_assert( 0 - start == 0 );
is.seekg( 0, std::ios::end);
const size_t buf_size = (size_t)is.tellg();
const size_t rgb_buf_size = buf_size * 3 / 2;
unsigned char *dummy_buffer = new unsigned char[buf_size];
is.seekg(start, std::ios::beg);
is.read( (char*)dummy_buffer, buf_size);
is.seekg(start, std::ios::beg);
gdcm_assert( !(rgb_buf_size % 3) );
gdcm_assert( !(buf_size % 2) );
unsigned char *copy = new unsigned char[ rgb_buf_size ];
const size_t size = buf_size/4;
for (size_t j = 0; j < size; ++j)
{
unsigned char ybr422[4];
ybr422[0] = dummy_buffer[4*j+0];
ybr422[1] = dummy_buffer[4*j+1];
ybr422[2] = dummy_buffer[4*j+2];
ybr422[3] = dummy_buffer[4*j+3];
#if 0#else
unsigned char ybr[6]; ybr[0] = ybr422[0];
ybr[1] = ybr422[2];
ybr[2] = ybr422[3];
ybr[3] = ybr422[1];
ybr[4] = ybr422[2];
ybr[5] = ybr422[3];
memcpy(copy + 6 * j, ybr, 6 );
#endif
}
os.write((char*)copy, rgb_buf_size);
delete[] copy;
delete[] dummy_buffer;
return true;
}
bool ImageCodec::DoPlanarConfiguration(std::istream &is, std::ostream &os)
{
std::streampos start = is.tellg();
gdcm_assert( 0 - start == 0 );
is.seekg( 0, std::ios::end);
size_t buf_size = (size_t)is.tellg();
char *dummy_buffer = new char[(unsigned int)buf_size];
is.seekg(start, std::ios::beg);
is.read( dummy_buffer, buf_size);
is.seekg(start, std::ios::beg);
gdcm_assert( buf_size % 3 == 0 );
unsigned long size = (unsigned long)buf_size/3;
char *copy = new char[ (unsigned int)buf_size ];
const char *r = dummy_buffer ;
const char *g = dummy_buffer + size;
const char *b = dummy_buffer + size + size;
char *p = copy ;
for (unsigned long j = 0; j < size; ++j)
{
*(p++) = *(r++);
*(p++) = *(g++);
*(p++) = *(b++);
}
delete[] dummy_buffer ;
os.write(copy , buf_size);
delete[] copy;
return true;
}
bool ImageCodec::DoSimpleCopy(std::istream &is, std::ostream &os)
{
#if 1
std::streampos start = is.tellg();
gdcm_assert( 0 - start == 0 );
is.seekg( 0, std::ios::end);
size_t buf_size = (size_t)is.tellg();
char *dummy_buffer = new char[(unsigned int)buf_size];
is.seekg(start, std::ios::beg);
is.read( dummy_buffer, buf_size);
is.seekg(start, std::ios::beg); os.write( dummy_buffer, buf_size);
delete[] dummy_buffer ;
#else#endif
return true;
}
bool ImageCodec::DoPaddedCompositePixelCode(std::istream &is, std::ostream &os)
{
std::streampos start = is.tellg();
gdcm_assert( 0 - start == 0 );
is.seekg( 0, std::ios::end);
size_t buf_size = (size_t)is.tellg();
char *dummy_buffer = new char[(unsigned int)buf_size];
is.seekg(start, std::ios::beg);
is.read( dummy_buffer, buf_size);
is.seekg(start, std::ios::beg);
gdcm_assert( !(buf_size % 2) );
bool ret = true;
if( GetPixelFormat().GetBitsAllocated() == 16 )
{
for(size_t i = 0; i < buf_size/2; ++i)
{
#ifdef GDCM_WORDS_BIGENDIAN
os.write( dummy_buffer+i, 1 );
os.write( dummy_buffer+i+buf_size/2, 1 );
#else
os.write( dummy_buffer+i+buf_size/2, 1 );
os.write( dummy_buffer+i, 1 );
#endif
}
}
else if( GetPixelFormat().GetBitsAllocated() == 32 )
{
gdcm_assert( !(buf_size % 4) );
for(size_t i = 0; i < buf_size/4; ++i)
{
#ifdef GDCM_WORDS_BIGENDIAN
os.write( dummy_buffer+i, 1 );
os.write( dummy_buffer+i+1*buf_size/4, 1 );
os.write( dummy_buffer+i+2*buf_size/4, 1 );
os.write( dummy_buffer+i+3*buf_size/4, 1 );
#else
os.write( dummy_buffer+i+3*buf_size/4, 1 );
os.write( dummy_buffer+i+2*buf_size/4, 1 );
os.write( dummy_buffer+i+1*buf_size/4, 1 );
os.write( dummy_buffer+i, 1 );
#endif
}
}
else
{
ret = false;
}
delete[] dummy_buffer;
return ret;
}
bool ImageCodec::DoInvertMonochrome(std::istream &is, std::ostream &os)
{
if ( PF.GetPixelRepresentation() )
{
if ( PF.GetBitsAllocated() == 8 )
{
uint8_t c;
while( is.read((char*)&c,1) )
{
c = (uint8_t)(255 - c);
os.write((char*)&c, 1 );
}
}
else if ( PF.GetBitsAllocated() == 16 )
{
gdcm_assert( PF.GetBitsStored() != 12 );
uint16_t smask16 = 65535;
uint16_t c;
while( is.read((char*)&c,2) )
{
c = (uint16_t)(smask16 - c);
os.write((char*)&c, 2);
}
}
}
else
{
if ( PF.GetBitsAllocated() == 8 )
{
uint8_t c;
while( is.read((char*)&c,1) )
{
c = (uint8_t)(255 - c);
os.write((char*)&c, 1);
}
}
else if ( PF.GetBitsAllocated() == 16 )
{
uint16_t mask = 1;
for (int j=0; j<PF.GetBitsStored()-1; ++j)
{
mask = (uint16_t)((mask << 1) + 1); }
uint16_t c;
while( is.read((char*)&c,2) )
{
if( c > mask )
{
gdcmWarningMacro( "Bogus max value: "<< c << " max should be at most: " << mask
<< " results will be truncated. Use at own risk");
c = mask;
}
gdcm_assert( c <= mask );
c = (uint16_t)(mask - c);
gdcm_assert( c <= mask );
os.write((char*)&c, 2);
}
}
}
return true;
}
bool ImageCodec::CleanupUnusedBits(char * data8, size_t datalen)
{
if( !NeedOverlayCleanup ) return true;
void * data = data8;
gdcm_assert( PF.GetBitsAllocated() > 8 );
if( PF.GetBitsAllocated() == 16 )
{
uint16_t pmask = 0xffff;
pmask = (uint16_t)(pmask >> ( PF.GetBitsAllocated() - PF.GetBitsStored() ));
if( PF.GetPixelRepresentation() )
{
uint16_t smask = 0x0001;
smask = (uint16_t)(
smask << ( 16 - (PF.GetBitsAllocated() - PF.GetBitsStored() + 1) ));
int16_t nmask = (int16_t)0x8000;
nmask = (int16_t)(nmask >> ( PF.GetBitsAllocated() - PF.GetBitsStored() - 1 ));
uint16_t *start = (uint16_t*)data;
for( uint16_t *p = start ; p != start + datalen / 2; ++p )
{
uint16_t c = *p;
c = (uint16_t)(c >> (PF.GetBitsStored() - PF.GetHighBit() - 1));
if ( c & smask )
{
c = (uint16_t)(c | nmask);
}
else
{
c = c & pmask;
}
*p = c;
}
}
else {
uint16_t *start = (uint16_t*)data;
for( uint16_t *p = start ; p != start + datalen / 2; ++p )
{
uint16_t c = *p;
c = (uint16_t)(
(c >> (PF.GetBitsStored() - PF.GetHighBit() - 1)) & pmask);
*p = c;
}
}
}
else if (PF.GetBitsAllocated() == 32) {
uint32_t pmask = 0xffffffff;
pmask = (uint32_t)(pmask >> (PF.GetBitsAllocated() - PF.GetBitsStored()));
if (PF.GetPixelRepresentation()) {
uint32_t smask = 0x00000001;
smask = (uint32_t)(smask << (32 - (PF.GetBitsAllocated() -
PF.GetBitsStored() + 1)));
int32_t nmask = (int32_t)0x80000000;
nmask =
(int32_t)(nmask >> (PF.GetBitsAllocated() - PF.GetBitsStored() - 1));
uint32_t *start = (uint32_t *)data;
for (uint32_t *p = start; p != start + datalen / 4; ++p) {
uint32_t c = *p;
c = (uint32_t)(c >> (PF.GetBitsStored() - PF.GetHighBit() - 1));
if (c & smask) {
c = (uint32_t)(c | nmask);
} else {
c = c & pmask;
}
*p = c;
}
} else {
uint32_t *start = (uint32_t *)data;
for (uint32_t *p = start; p != start + datalen / 4; ++p) {
uint32_t c = *p;
c = (uint32_t)((c >> (PF.GetBitsStored() - PF.GetHighBit() - 1)) &
pmask);
*p = c;
}
}
}
else
{
gdcm_assert(0); return false;
}
return true;
}
bool ImageCodec::DoOverlayCleanup(std::istream &is, std::ostream &os)
{
gdcm_assert( PF.GetBitsAllocated() > 8 );
if( PF.GetBitsAllocated() == 16 )
{
uint16_t pmask = 0xffff;
pmask = (uint16_t)(pmask >> ( PF.GetBitsAllocated() - PF.GetBitsStored() ));
if( PF.GetPixelRepresentation() )
{
uint16_t smask = 0x0001;
smask = (uint16_t)(
smask << ( 16 - (PF.GetBitsAllocated() - PF.GetBitsStored() + 1) ));
int16_t nmask = (int16_t)0x8000;
nmask = (int16_t)(nmask >> ( PF.GetBitsAllocated() - PF.GetBitsStored() - 1 ));
uint16_t c;
while( is.read((char*)&c,2) )
{
c = (uint16_t)(c >> (PF.GetBitsStored() - PF.GetHighBit() - 1));
if ( c & smask )
{
c = (uint16_t)(c | nmask);
}
else
{
c = c & pmask;
}
os.write((char*)&c, 2 );
}
}
else {
const unsigned int bufferSize = 1024;
std::vector<uint16_t> buffer(bufferSize);
while (is)
{
is.read((char *)buffer.data(), bufferSize * sizeof(uint16_t));
std::streamsize bytesRead = is.gcount();
std::vector<uint16_t>::iterator validBufferEnd = buffer.begin() + bytesRead / sizeof(uint16_t);
for (std::vector<uint16_t>::iterator it = buffer.begin(); it != validBufferEnd; ++it)
{
*it = ((*it >> (PF.GetBitsStored() - PF.GetHighBit() - 1)) & pmask);
}
os.write((char *)buffer.data(), bytesRead);
}
}
}
else if (PF.GetBitsAllocated() == 32) {
uint16_t pmask = 0xffff;
pmask = (uint16_t)(pmask >> (PF.GetBitsAllocated() - PF.GetBitsStored()));
if (PF.GetPixelRepresentation()) {
uint16_t smask = 0x0001;
smask = (uint16_t)(smask << (16 - (PF.GetBitsAllocated() -
PF.GetBitsStored() + 1)));
int16_t nmask = (int16_t)0x8000;
nmask =
(int16_t)(nmask >> (PF.GetBitsAllocated() - PF.GetBitsStored() - 1));
uint16_t c;
while (is.read((char *)&c, 2)) {
c = (uint16_t)(c >> (PF.GetBitsStored() - PF.GetHighBit() - 1));
if (c & smask) {
c = (uint16_t)(c | nmask);
} else {
c = c & pmask;
}
os.write((char *)&c, 2);
}
} else {
const unsigned int bufferSize = 1024;
std::vector<uint16_t> buffer(bufferSize);
while (is) {
is.read((char *)buffer.data(), bufferSize * sizeof(uint16_t));
std::streamsize bytesRead = is.gcount();
std::vector<uint16_t>::iterator validBufferEnd =
buffer.begin() + bytesRead / sizeof(uint16_t);
for (std::vector<uint16_t>::iterator it = buffer.begin();
it != validBufferEnd; ++it) {
*it = ((*it >> (PF.GetBitsStored() - PF.GetHighBit() - 1)) & pmask);
}
os.write((char *)buffer.data(), bytesRead);
}
}
}
else
{
gdcm_assert(0); return false;
}
return true;
}
bool ImageCodec::Decode(DataElement const &, DataElement &)
{
return true;
}
bool ImageCodec::DecodeByStreams(std::istream &is, std::ostream &os)
{
gdcm_assert( PlanarConfiguration == 0 || PlanarConfiguration == 1);
gdcm_assert( PI != PhotometricInterpretation::UNKNOWN );
std::stringstream bs_os; std::stringstream pcpc_os; std::stringstream pl_os; std::istream *cur_is = &is;
if( NeedByteSwap )
{
DoByteSwap(*cur_is,bs_os);
cur_is = &bs_os;
}
if ( RequestPaddedCompositePixelCode )
{
DoPaddedCompositePixelCode(*cur_is,pcpc_os);
cur_is = &pcpc_os;
}
switch(PI)
{
case PhotometricInterpretation::MONOCHROME2:
case PhotometricInterpretation::RGB:
case PhotometricInterpretation::ARGB:
break;
case PhotometricInterpretation::MONOCHROME1:
break;
case PhotometricInterpretation::YBR_FULL:
{
const JPEGCodec *c = dynamic_cast<const JPEGCodec*>(this);
if( c )
{
}
}
break;
case PhotometricInterpretation::PALETTE_COLOR:
break;
case PhotometricInterpretation::YBR_FULL_422:
case PhotometricInterpretation::YBR_PARTIAL_422:
{
const JPEGCodec *c = dynamic_cast<const JPEGCodec*>(this);
if( !c )
{
DoYBRFull422(*cur_is,pl_os);
cur_is = &pl_os;
}
}
break;
case PhotometricInterpretation::YBR_ICT:
break;
case PhotometricInterpretation::YBR_RCT:
break;
default:
gdcmErrorMacro( "Unhandled PhotometricInterpretation: " << PI );
return false;
}
if( RequestPlanarConfiguration )
{
DoPlanarConfiguration(*cur_is,pl_os);
cur_is = &pl_os;
}
bool copySuccess = false;
if ( PF.GetBitsAllocated() != PF.GetBitsStored()
&& PF.GetBitsAllocated() != 8 )
{
if( NeedOverlayCleanup )
{
copySuccess = DoOverlayCleanup(*cur_is, os);
}
else
{
copySuccess = DoSimpleCopy(*cur_is, os);
}
}
else
{
gdcm_assert( PF.GetBitsAllocated() == PF.GetBitsStored() );
copySuccess = DoSimpleCopy(*cur_is, os);
}
return copySuccess;
}
bool ImageCodec::IsValid(PhotometricInterpretation const &)
{
return false;
}
void ImageCodec::SetDimensions(const unsigned int d[3])
{
Dimensions[0] = d[0];
Dimensions[1] = d[1];
Dimensions[2] = d[2];
}
void ImageCodec::SetDimensions(const std::vector<unsigned int> & d)
{
size_t theSize = d.size();
gdcm_assert(theSize<= 3);
for (size_t i = 0; i < 3; i++)
{
if (i < theSize)
Dimensions[i] = d[i];
else
Dimensions[i] = 1;
}
}
bool ImageCodec::StartEncode( std::ostream & )
{
gdcm_assert(0);
return false;
}
bool ImageCodec::IsRowEncoder()
{
return false;
}
bool ImageCodec::IsFrameEncoder()
{
return false;
}
bool ImageCodec::AppendRowEncode( std::ostream & , const char * , size_t )
{
gdcm_assert(0);
return false;
}
bool ImageCodec::AppendFrameEncode( std::ostream & , const char * , size_t )
{
gdcm_assert(0);
return false;
}
bool ImageCodec::StopEncode( std::ostream & )
{
gdcm_assert(0);
return false;
}
}