#include "gdcmRLECodec.h"
#include "gdcmTransferSyntax.h"
#include "gdcmTrace.h"
#include "gdcmByteSwap.txx"
#include "gdcmDataElement.h"
#include "gdcmSequenceOfFragments.h"
#include "gdcmSmartPointer.h"
#include "gdcmSwapper.h"
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <vector>
#include <array>
#include <gdcmrle/rle.h>
namespace gdcm
{
class RLEHeader
{
private:
uint32_t NumSegments = 0;
uint32_t Offset[15] = {0};
public:
uint32_t GetNumSegments() const { return NumSegments; }
bool SetNumSegments(uint32_t num)
{
if (num > 15)
{
gdcmErrorMacro("Number of segments cannot be bigger than 15");
return false;
}
NumSegments = num;
return true;
};
bool SetOffset(const std::array<uint32_t, 15> &offset)
{
std::copy(offset.begin(), offset.end(), Offset);
return true;
};
uint32_t GetOffset(size_t index) const
{
if (index < 15) return Offset[index];
return 0;
};
bool SetOffset(size_t index, uint32_t value) {
if (index >= 15) return false;
Offset[index] = value;
return true;
}
bool Read(std::istream &is)
{
uint32_t buffer[16] = {0};
is.read(reinterpret_cast<char *>(buffer), 64);
if (static_cast<size_t>(is.gcount()) != 64)
{
gdcmErrorMacro("RLE Header truncated: expected 64 bytes, got " << is.gcount());
return false;
}
gdcm_assert(sizeof(uint32_t) * 16 == 64);
SwapperNoOp::SwapArray(reinterpret_cast<uint32_t *>(buffer), 16);
if (!SetNumSegments(buffer[0])) return false;
memcpy(Offset, &buffer[1], sizeof(uint32_t) * 15);
if (NumSegments >= 1) {
if (Offset[0] != 64) return false;
}
return true;
}
void Print(std::ostream &os)
{
os << "NumSegments:" << NumSegments << "\n";
for (int i = 0; i < 15; ++i) {
os << i << ":" << Offset[i] << "\n";
}
}
};
static_assert(sizeof(RLEHeader) == 64, "RLEHeader size must be 64 bits to comply with dicom standard");
class RLEFrame
{
public:
bool Read(std::istream &is)
{
return Header.Read(is);
}
void Print(std::ostream &os)
{
Header.Print(os);
}
RLEHeader Header;
std::vector<char> Bytes;
};
class RLEInternals
{
public:
RLEFrame Frame;
std::vector<uint32_t> SegmentLength;
};
RLECodec::RLECodec()
{
Internals = new RLEInternals;
Length = 0;
BufferLength = 0;
}
RLECodec::~RLECodec()
{
delete Internals;
}
bool RLECodec::CanDecode(TransferSyntax const &ts) const
{
return ts == TransferSyntax::RLELossless;
}
bool RLECodec::CanCode(TransferSyntax const &ts) const
{
return ts == TransferSyntax::RLELossless;
}
inline int count_identical_bytes(const char *start, size_t len)
{
gdcm_assert( len );
#if 0#else
const char ref = start[0];
unsigned int count = 1; const size_t cmin = std::min((size_t)128,len);
while( count < cmin && start[count] == ref )
{
++count;
}
gdcm_assert( count <= 128 ); gdcm_assert( count >= 1 );
return count;
#endif
}
inline int count_nonrepetitive_bytes(const char *start, size_t len)
{
gdcm_assert( len );
#if 0#else
unsigned int count = 1;
const size_t cmin = std::min((size_t)128,len);
#if 0#else
#if 1
for( count = 1; count < cmin; ++count )
{
if( start[count] == start[count-1] )
{
if( count + 1 < cmin && start[count] != start[count+1] )
{
continue;
}
--count; break;
}
}
#else#endif
#endif
gdcm_assert( 1 <= count && count <= 128 );
return count;
#endif
}
ptrdiff_t rle_encode(char *output, size_t outputlength, const char *input, size_t inputlength)
{
char *pout = output;
const char *pin = input;
size_t length = inputlength;
while( pin != input + inputlength )
{
gdcm_assert( length <= inputlength );
gdcm_assert( pin <= input + inputlength );
int count = count_identical_bytes(pin, length);
if( count > 1 )
{
if( pout + 1 + 1 > output + outputlength ) return -1;
*pout = (char)(-count + 1);
gdcm_assert( 1 - *pout == count );
gdcm_assert( *pout <= -1 && *pout >= -127 );
++pout;
*pout = *pin;
++pout;
}
else
{
count = count_nonrepetitive_bytes(pin, length);
if( pout + count + 1 > output + outputlength ) return -1;
*pout = (char)(count - 1);
gdcm_assert( *pout != -128 && *pout+1 == count );
gdcm_assert( *pout >= 0 );
++pout;
memcpy(pout, pin, count);
pout += count;
}
pin += count;
gdcm_assert( count <= (int)length );
length -= count;
}
return pout - output;
}
template <typename T>
bool DoInvertPlanarConfiguration(T *output, const T *input, uint32_t inputlength)
{
const T *r = input+0;
const T *g = input+1;
const T *b = input+2;
uint32_t length = (inputlength / 3) * 3; gdcm_assert( length == inputlength || length == inputlength - 1 );
gdcm_assert( length % 3 == 0 );
uint32_t plane_length = length / 3;
T *pout = output;
while( pout != output + plane_length * 1 )
{
*pout++ = *r;
r += 3;
}
gdcm_assert( r == input + length );
gdcm_assert( pout == output + plane_length );
while( pout != output + plane_length * 2 )
{
*pout++ = *g;
g += 3;
}
gdcm_assert( g == input + length + 1);
gdcm_assert( pout == output + 2*plane_length );
while( pout != output + plane_length * 3 )
{
*pout++ = *b;
b += 3;
}
gdcm_assert( b == input + length + 2);
assert ( pout == output + length );
return true;
}
bool RLECodec::Code(DataElement const &in, DataElement &out)
{
const unsigned int *dims = this->GetDimensions();
const unsigned int n = 256*256;
char *outbuf;
char small_buffer[n];
outbuf = small_buffer;
SmartPointer<SequenceOfFragments> sq = new SequenceOfFragments;
const Tag itemStart(0xfffe, 0xe000);
const ByteValue *bv = in.GetByteValue();
gdcm_assert( bv );
const char *input = bv->GetPointer();
unsigned long bvl = bv->GetLength();
unsigned long image_len = bvl / dims[2];
char *buffer = nullptr;
char *bufferrgb = nullptr;
if( GetPixelFormat().GetBitsAllocated() > 8 )
{
buffer = new char [ image_len ];
}
if ( GetPhotometricInterpretation() == PhotometricInterpretation::RGB
|| GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL
|| GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT
|| GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 )
{
bufferrgb = new char [ image_len ];
}
unsigned int MaxNumSegments = 1;
if( GetPixelFormat().GetBitsAllocated() == 8 )
{
MaxNumSegments *= 1;
}
else if( GetPixelFormat().GetBitsAllocated() == 16 )
{
MaxNumSegments *= 2;
}
else if( GetPixelFormat().GetBitsAllocated() == 32 )
{
MaxNumSegments *= 4;
}
else
{
delete[] buffer;
delete[] bufferrgb;
return false;
}
if( GetPhotometricInterpretation() == PhotometricInterpretation::RGB
|| GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL
|| GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT
|| GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 )
{
MaxNumSegments *= 3;
}
gdcm_assert( GetPixelFormat().GetBitsAllocated() == 8 || GetPixelFormat().GetBitsAllocated() == 16
|| GetPixelFormat().GetBitsAllocated() == 32 );
if( GetPixelFormat().GetSamplesPerPixel() == 3 )
{
gdcm_assert( MaxNumSegments % 3 == 0 );
}
RLEHeader header;
header.SetNumSegments(static_cast<uint32_t>(MaxNumSegments));
header.SetOffset({64});
for(unsigned int dim = 0; dim < dims[2]; ++dim)
{
const char *ptr_img = input + dim * image_len;
if( GetPlanarConfiguration() == 0 && GetPixelFormat().GetSamplesPerPixel() == 3 )
{
if( GetPixelFormat().GetBitsAllocated() == 8 )
{
DoInvertPlanarConfiguration<char>(bufferrgb, ptr_img, (uint32_t)(image_len / sizeof(char)));
}
else if ( GetPixelFormat().GetBitsAllocated() == 16 )
{
DoInvertPlanarConfiguration<short>((short*)(void*)bufferrgb, (const short*)(const void*)ptr_img, (uint32_t)(image_len / sizeof(short)));
}
else
{
gdcm_assert( GetPixelFormat().GetBitsAllocated() == 32 );
DoInvertPlanarConfiguration<int32_t>(
(int32_t*)(void*)bufferrgb,
(const int32_t*)(const void*)ptr_img,
(uint32_t)(image_len / sizeof(int32_t))
);
}
ptr_img = bufferrgb;
}
if( GetPixelFormat().GetBitsAllocated() == 32 )
{
gdcm_assert( !(image_len % 4) );
unsigned int div = GetPixelFormat().GetSamplesPerPixel();
for(unsigned int j = 0; j < div; ++j)
{
unsigned long iimage_len = image_len / div;
char *ibuffer = buffer + j * iimage_len;
const char *iptr_img = ptr_img + j * iimage_len;
gdcm_assert( iimage_len % 4 == 0 );
for(unsigned long i = 0; i < iimage_len/4; ++i)
{
#ifdef GDCM_WORDS_BIGENDIAN
ibuffer[i] = iptr_img[4*i+0];
#else
ibuffer[i] = iptr_img[4*i+3];
#endif
}
for(unsigned long i = 0; i < iimage_len/4; ++i)
{
#ifdef GDCM_WORDS_BIGENDIAN
ibuffer[i+iimage_len/4] = iptr_img[4*i+1];
#else
ibuffer[i+iimage_len/4] = iptr_img[4*i+2];
#endif
}
for(unsigned long i = 0; i < iimage_len/4; ++i)
{
#ifdef GDCM_WORDS_BIGENDIAN
ibuffer[i+2*iimage_len/4] = iptr_img[4*i+2];
#else
ibuffer[i+2*iimage_len/4] = iptr_img[4*i+1];
#endif
}
for(unsigned long i = 0; i < iimage_len/4; ++i)
{
#ifdef GDCM_WORDS_BIGENDIAN
ibuffer[i+3*iimage_len/4] = iptr_img[4*i+3];
#else
ibuffer[i+3*iimage_len/4] = iptr_img[4*i+0];
#endif
}
}
ptr_img = buffer;
}
else if( GetPixelFormat().GetBitsAllocated() == 16 )
{
gdcm_assert( !(image_len % 2) );
unsigned int div = GetPixelFormat().GetSamplesPerPixel();
for(unsigned int j = 0; j < div; ++j)
{
unsigned long iimage_len = image_len / div;
char *ibuffer = buffer + j * iimage_len;
const char *iptr_img = ptr_img + j * iimage_len;
gdcm_assert( iimage_len % 2 == 0 );
for(unsigned long i = 0; i < iimage_len/2; ++i)
{
#ifdef GDCM_WORDS_BIGENDIAN
ibuffer[i] = iptr_img[2*i];
#else
ibuffer[i] = iptr_img[2*i+1];
#endif
}
for(unsigned long i = 0; i < iimage_len/2; ++i)
{
#ifdef GDCM_WORDS_BIGENDIAN
ibuffer[i+iimage_len/2] = iptr_img[2*i+1];
#else
ibuffer[i+iimage_len/2] = iptr_img[2*i];
#endif
}
}
ptr_img = buffer;
}
gdcm_assert( image_len % MaxNumSegments == 0 );
const size_t input_seg_length = image_len / MaxNumSegments;
std::string datastr;
for(unsigned int seg = 0; seg < MaxNumSegments; ++seg )
{
size_t partition = input_seg_length;
const char *ptr = ptr_img + seg * input_seg_length;
gdcm_assert( ptr < ptr_img + image_len );
if( seg == MaxNumSegments - 1 )
{
partition += image_len % MaxNumSegments;
gdcm_assert( (MaxNumSegments-1) * input_seg_length + partition == (size_t)image_len );
}
gdcm_assert( partition == input_seg_length );
std::stringstream data;
gdcm_assert( partition % dims[1] == 0 );
size_t length = 0;
for(unsigned int y = 0; y < dims[1]; ++y)
{
ptrdiff_t llength = rle_encode(outbuf, n, ptr + y*dims[0], partition / dims[1] );
if( llength < 0 )
{
gdcmErrorMacro( "RLE compressor error" );
delete[] buffer;
delete[] bufferrgb;
return false;
}
gdcm_assert( llength );
data.write((char*)outbuf, llength);
length += llength;
}
header.SetOffset(1 + seg, (uint32_t)(header.GetOffset(seg) + length));
gdcm_assert( data.str().size() == length );
datastr += data.str();
}
header.SetOffset(MaxNumSegments, 0);
std::stringstream os;
os.write((char*)&header,sizeof(header));
std::string str = os.str() + datastr;
gdcm_assert( !str.empty() );
Fragment frag;
VL::Type strSize = (VL::Type)str.size();
frag.SetByteValue( str.data(), strSize );
sq->AddFragment( frag );
}
out.SetValue( *sq );
delete[] buffer;
delete[] bufferrgb;
return true;
}
size_t RLECodec::DecodeFragment(Fragment const & frag, char *buffer, size_t llen)
{
std::stringstream is;
const ByteValue &bv = dynamic_cast<const ByteValue&>(frag.GetValue());
size_t bv_len = bv.GetLength();
char *mybuffer = new char[bv_len];
bv.GetBuffer(mybuffer, bv.GetLength());
is.write(mybuffer, bv.GetLength());
delete[] mybuffer;
std::stringstream os;
SetLength( (unsigned long)llen );
#if !defined(NDEBUG)
const unsigned int * const dimensions = this->GetDimensions();
const PixelFormat & pf = this->GetPixelFormat();
gdcm_assert( llen == dimensions[0] * dimensions[1] * pf.GetPixelSize() );
#endif
bool r = DecodeByStreams(is, os);
if( !r ) return 0;
(void)r; std::streampos p = is.tellg();
if( !!is )
{
std::streamoff check = bv.GetLength() - p;
if( check ) { gdcmDebugMacro( "tiny offset detected in between RLE segments: " << check ); }
}
else
{
gdcmWarningMacro( "Bad RLE stream" );
}
std::string::size_type check = os.str().size();
memcpy(buffer, os.str().c_str(), check);
return check;
}
bool RLECodec::Decode(DataElement const &in, DataElement &out)
{
if( NumberOfDimensions == 2 )
{
out = in;
const SequenceOfFragments *sf = in.GetSequenceOfFragments();
if( !sf ) return false;
unsigned long len = GetBufferLength();
std::stringstream is;
sf->WriteBuffer( is );
SetLength( len );
std::stringstream os;
bool r = DecodeByStreams(is, os);
if( !r )
{
gdcmErrorMacro( "DecodeByStreams failure." );
return false;
}
std::string str = os.str();
std::string::size_type check = str.size();
gdcm_assert( check == len );
VL::Type checkCast = (VL::Type)check;
out.SetByteValue( str.data(), checkCast );
return true;
}
else if ( NumberOfDimensions == 3 )
{
out = in;
const SequenceOfFragments *sf = in.GetSequenceOfFragments();
if( !sf ) return false;
const unsigned long len = GetBufferLength();
unsigned long pos = 0;
const size_t nframes = sf->GetNumberOfFragments();
const size_t zdim = Dimensions[2];
if( nframes != zdim )
{
gdcmErrorMacro( "Invalid number of fragments: " << nframes << " should be: " << zdim );
return false;
}
char *buffer = new char[len];
const std::size_t llen = len / nframes;
bool corruption = false;
for(unsigned int i = 0; i < nframes; ++i)
{
const Fragment &frag = sf->GetFragment(i);
const size_t check = DecodeFragment(frag, buffer + pos, llen); (void)check;
if( check != llen )
{
gdcmDebugMacro( "RLE pb with frag: " << i );
corruption = true;
}
pos += (unsigned long)llen;
}
if( !corruption )
gdcm_assert( pos == len );
out.SetByteValue( buffer, (uint32_t)len );
delete[] buffer;
return !corruption;
}
return false;
}
bool RLECodec::DecodeExtent(
char *buffer,
unsigned int xmin, unsigned int xmax,
unsigned int ymin, unsigned int ymax,
unsigned int zmin, unsigned int zmax,
std::istream & is
)
{
std::stringstream tmpos;
BasicOffsetTable bot;
bot.Read<SwapperNoOp>( is );
const unsigned int * dimensions = this->GetDimensions();
const PixelFormat & pf = this->GetPixelFormat();
gdcm_assert( pf.GetBitsAllocated() % 8 == 0 );
gdcm_assert( pf != PixelFormat::SINGLEBIT );
gdcm_assert( pf != PixelFormat::UINT12 && pf != PixelFormat::INT12 );
std::stringstream os;
Fragment frag;
for( unsigned int z = 0; z < zmin; ++z )
{
frag.ReadPreValue<SwapperNoOp>(is);
std::streamoff off = frag.GetVL();
is.seekg( off, std::ios::cur );
}
for( unsigned int z = zmin; z <= zmax; ++z )
{
frag.ReadPreValue<SwapperNoOp>(is);
std::streampos start = is.tellg();
SetLength( dimensions[0] * dimensions[1] * pf.GetPixelSize() );
const bool r = DecodeByStreams(is, os); (void)r;
if( !r ) return false;
gdcm_assert( r );
std::streampos end = is.tellg();
size_t numberOfReadBytes = (size_t)(end - start);
if( numberOfReadBytes > frag.GetVL() )
{
size_t diff = numberOfReadBytes - frag.GetVL();
gdcm_assert( diff == 1 );
os.seekp( 0 - (int)diff, std::ios::cur );
os.put( 0 );
end = (size_t)end - 1;
}
gdcm_assert( end - start == frag.GetVL() || (size_t)(end - start) + 1 == frag.GetVL() );
if( (end - start) % 2 == 1 )
{
is.get();
}
}
os.seekg(0, std::ios::beg );
gdcm_assert( os.good() );
std::istream *theStream = &os;
unsigned int rowsize = xmax - xmin + 1;
unsigned int colsize = ymax - ymin + 1;
unsigned int bytesPerPixel = pf.GetPixelSize();
std::vector<char> buffer1;
buffer1.resize( rowsize*bytesPerPixel );
char *tmpBuffer1 = buffer1.data();
unsigned int y, z;
std::streamoff theOffset;
for (z = zmin; z <= zmax; ++z)
{
for (y = ymin; y <= ymax; ++y)
{
theStream->seekg(std::ios::beg);
theOffset = 0 + ((z-zmin)*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel;
theStream->seekg(theOffset);
theStream->read(tmpBuffer1, rowsize*bytesPerPixel);
memcpy(&(buffer[((z-zmin)*rowsize*colsize +
(y-ymin)*rowsize)*bytesPerPixel]),
tmpBuffer1, rowsize*bytesPerPixel);
}
}
return true;
}
bool RLECodec::DecodeByStreamsCommon(std::istream &, std::ostream &)
{
return false;
}
bool RLECodec::DecodeByStreams(std::istream &is, std::ostream &os)
{
std::streampos start = is.tellg();
char dummy_buffer[256];
std::stringstream tmpos;
RLEFrame &frame = Internals->Frame;
if( !frame.Read(is) )
return false;
unsigned long numSegments = frame.Header.GetNumSegments();
unsigned long length = Length;
gdcm_assert( length );
gdcm_assert( GetPixelFormat().GetBitsAllocated() == 32 ||
GetPixelFormat().GetBitsAllocated() == 16 ||
GetPixelFormat().GetBitsAllocated() == 8 );
if( GetPixelFormat().GetBitsAllocated() > 8 )
{
RequestPaddedCompositePixelCode = true;
}
gdcm_assert( GetPixelFormat().GetSamplesPerPixel() == 3 || GetPixelFormat().GetSamplesPerPixel() == 1 );
if( GetPixelFormat().GetSamplesPerPixel() == 3 && GetPlanarConfiguration() == 0 )
{
RequestPlanarConfiguration = true;
}
length /= numSegments;
for(unsigned long i = 0; i<numSegments; ++i)
{
unsigned long numberOfReadBytes = 0;
std::streampos pos = is.tellg() - start;
if (frame.Header.GetOffset(i) > BufferLength)
{
gdcmErrorMacro("Offset is bigger then buffer Length");
return false;
}
if ( frame.Header.GetOffset(i) - pos != 0 )
{
std::streamoff check = frame.Header.GetOffset(i) - pos; (void)check; is.seekg(frame.Header.GetOffset(i) + start, std::ios::beg);
}
unsigned long numOutBytes = 0;
signed char byte;
while( numOutBytes < length )
{
is.read((char*)&byte, 1);
if( !is.good() )
{
gdcmErrorMacro( "Could not decode" );
return false;
}
numberOfReadBytes++;
if( byte >= 0 )
{
is.read( dummy_buffer, byte+1 );
numberOfReadBytes += byte+1;
numOutBytes += byte+ 1;
tmpos.write( dummy_buffer, byte+1 );
}
else if( byte <= -1 && byte >= -127 )
{
char nextByte;
is.read( &nextByte, 1);
numberOfReadBytes += 1;
memset(dummy_buffer, nextByte, -byte + 1);
numOutBytes += -byte + 1;
tmpos.write( dummy_buffer, -byte+1 );
}
else
{
gdcm_assert( byte == -128 );
}
}
if( numOutBytes != length ) return false;
}
return ImageCodec::DecodeByStreams(tmpos,os);
}
bool RLECodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts)
{
RLEFrame frame;
if( !frame.Read(is) )
return false;
uint32_t bytespercomp = frame.Header.GetNumSegments();
if (frame.Header.GetNumSegments() % 3 == 0)
{
PI = PhotometricInterpretation::RGB;
PlanarConfiguration = 1;
this->PF.SetSamplesPerPixel( 3 );
bytespercomp /= 3;
}
else
{
PI = PhotometricInterpretation::MONOCHROME2;
this->PF.SetSamplesPerPixel( 1 );
}
this->PF.SetBitsAllocated( bytespercomp * 8 );
ts = TransferSyntax::RLELossless;
return true;
}
ImageCodec * RLECodec::Clone() const
{
return new RLECodec;
}
bool RLECodec::StartEncode( std::ostream & )
{
return true;
}
bool RLECodec::IsRowEncoder()
{
return false;
}
bool RLECodec::IsFrameEncoder()
{
return true;
}
class memsrc : public ::rle::source
{
public:
memsrc( const char * data, size_t datalen ):ptr(data),cur(data),len(datalen)
{
}
int read( char * out, int l ) override
{
memcpy( out, cur, l );
cur += l;
gdcm_assert( cur <= ptr + len );
return l;
}
streampos_t tell() override
{
gdcm_assert( cur <= ptr + len );
return (streampos_t)(cur - ptr);
}
bool seek(streampos_t pos) override
{
cur = ptr + pos;
gdcm_assert( cur <= ptr + len && cur >= ptr );
return true;
}
bool eof() override
{
gdcm_assert( cur <= ptr + len );
return cur == ptr + len;
}
memsrc * clone() override
{
memsrc * ret = new memsrc( ptr, len );
return ret;
}
private:
const char * ptr;
const char * cur;
size_t len;
};
bool RLECodec::AppendRowEncode( std::ostream & os, const char * data, size_t datalen)
{
(void)os; (void)data; (void)datalen;
gdcm_assert(0);
return false;
}
class streamdest : public rle::dest
{
public:
streamdest( std::ostream & os ):stream(os)
{
start = os.tellp();
}
int write( const char * in, int len ) override
{
stream.write(in, len );
return len;
}
bool seek( streampos_t abs_pos ) override
{
stream.seekp( abs_pos + start );
return true;
}
private:
std::ostream & stream;
std::streampos start;
};
bool RLECodec::AppendFrameEncode( std::ostream & out, const char * data, size_t datalen )
{
try {
const PixelFormat & pf = this->GetPixelFormat();
unsigned int pc = this->GetPlanarConfiguration();
bool isLittleEndian = !this->GetNeedByteSwap();
rle::pixel_info pi((unsigned char)pf.GetSamplesPerPixel(), (unsigned char)(pf.GetBitsAllocated()));
const unsigned int * dimensions = this->GetDimensions();
rle::image_info ii(dimensions[0], dimensions[1], pi, pc ? true : false, isLittleEndian);
const int h = dimensions[1];
memsrc src( data, datalen );
rle::rle_encoder re(src, ii);
streamdest fd( out );
if( !re.write_header( fd ) )
{
gdcmErrorMacro( "could not write header" );
return false;
}
for( int y = 0; y < h; ++y )
{
const int ret = re.encode_row( fd );
if( ret < 0 )
{
gdcmErrorMacro( "problem at row: " << y );
return false;
}
}
} catch( std::exception & ) {
gdcmErrorMacro( "invalid compression params (not supported for now)." );
return false;
}
return true;
}
bool RLECodec::StopEncode( std::ostream & )
{
return true;
}
}