674 lines
27 KiB
C++
674 lines
27 KiB
C++
/*
|
|
*
|
|
* Copyright (C) 1996-2016, OFFIS e.V.
|
|
* All rights reserved. See COPYRIGHT file for details.
|
|
*
|
|
* This software and supporting documentation were developed by
|
|
*
|
|
* OFFIS e.V.
|
|
* R&D Division Health
|
|
* Escherweg 2
|
|
* D-26121 Oldenburg, Germany
|
|
*
|
|
*
|
|
* Module: dcmimgle
|
|
*
|
|
* Author: Joerg Riesmeier
|
|
*
|
|
* Purpose: DicomInputPixelTemplate (Header)
|
|
*
|
|
*/
|
|
|
|
|
|
#ifndef DIINPXT_H
|
|
#define DIINPXT_H
|
|
|
|
#include "dcmtk/config/osconfig.h"
|
|
#include "dcmtk/dcmdata/dcpixel.h"
|
|
|
|
#include "dcmtk/ofstd/ofbmanip.h"
|
|
#include "dcmtk/ofstd/ofcast.h"
|
|
|
|
#include "dcmtk/dcmimgle/diinpx.h"
|
|
#include "dcmtk/dcmimgle/didocu.h"
|
|
#include "dcmtk/dcmimgle/dipxrept.h"
|
|
|
|
|
|
/*--------------------*
|
|
* helper functions *
|
|
*--------------------*/
|
|
|
|
static inline Uint8 expandSign(const Uint8 Value,
|
|
const Uint8,
|
|
const Uint8)
|
|
{
|
|
return Value;
|
|
}
|
|
|
|
|
|
static inline Uint16 expandSign(const Uint16 Value,
|
|
const Uint16,
|
|
const Uint16)
|
|
{
|
|
return Value;
|
|
}
|
|
|
|
|
|
static inline Uint32 expandSign(const Uint32 Value,
|
|
const Uint32,
|
|
const Uint32)
|
|
{
|
|
return Value;
|
|
}
|
|
|
|
|
|
static inline Sint8 expandSign(const Sint8 Value,
|
|
const Sint8 SignBit,
|
|
const Sint8 SignMask)
|
|
{
|
|
return (Value & SignBit) ? (Value | SignMask) : Value;
|
|
}
|
|
|
|
|
|
static inline Sint16 expandSign(const Sint16 Value,
|
|
const Sint16 SignBit,
|
|
const Sint16 SignMask)
|
|
{
|
|
return (Value & SignBit) ? (Value | SignMask) : Value;
|
|
}
|
|
|
|
|
|
static inline Sint32 expandSign(const Sint32 Value,
|
|
const Sint32 SignBit,
|
|
const Sint32 SignMask)
|
|
{
|
|
return (Value & SignBit) ? (Value | SignMask) : Value;
|
|
}
|
|
|
|
|
|
static Uint32 getPixelData(DcmPixelData *PixelData,
|
|
Uint8 *&pixel)
|
|
{
|
|
PixelData->getUint8Array(pixel);
|
|
return PixelData->getLength();
|
|
}
|
|
|
|
|
|
static Uint32 getPixelData(DcmPixelData *PixelData,
|
|
Uint16 *&pixel)
|
|
{
|
|
PixelData->getUint16Array(pixel);
|
|
return PixelData->getLength();
|
|
}
|
|
|
|
|
|
/*---------------------*
|
|
* class declaration *
|
|
*---------------------*/
|
|
|
|
/** Template class to convert DICOM pixel stream to intermediate representation
|
|
*/
|
|
template<class T1, class T2>
|
|
class DiInputPixelTemplate
|
|
: public DiInputPixel,
|
|
public DiPixelRepresentationTemplate<T2>
|
|
{
|
|
|
|
public:
|
|
|
|
/** constructor
|
|
*
|
|
** @param document pointer to DICOM image object
|
|
* @param alloc number of bits allocated for each pixel
|
|
* @param stored number of bits stored for each pixel
|
|
* @param high position of high bit within bits allocated
|
|
* @param first first frame to be processed
|
|
* @param number number of frames to be processed
|
|
* @param fsize number of pixels per frame (frame size)
|
|
* @param fileCache pointer to file cache object used for partial read
|
|
* @param fragment current pixel item fragment (for encapsulated pixel data)
|
|
*/
|
|
DiInputPixelTemplate(const DiDocument *document,
|
|
const Uint16 alloc,
|
|
const Uint16 stored,
|
|
const Uint16 high,
|
|
const unsigned long first,
|
|
const unsigned long number,
|
|
const unsigned long fsize,
|
|
DcmFileCache *fileCache,
|
|
Uint32 &fragment)
|
|
: DiInputPixel(stored, first, number, fsize),
|
|
Data(NULL)
|
|
{
|
|
MinValue[0] = 0;
|
|
MinValue[1] = 0;
|
|
MaxValue[0] = 0;
|
|
MaxValue[1] = 0;
|
|
if (this->isSigned())
|
|
{
|
|
AbsMinimum = -OFstatic_cast(double, DicomImageClass::maxval(Bits - 1, 0));
|
|
AbsMaximum = OFstatic_cast(double, DicomImageClass::maxval(Bits - 1));
|
|
} else {
|
|
AbsMinimum = 0;
|
|
AbsMaximum = OFstatic_cast(double, DicomImageClass::maxval(Bits));
|
|
}
|
|
if ((document != NULL) && (document->getPixelData() != NULL))
|
|
convert(document, alloc, stored, high, fileCache, fragment);
|
|
if ((PixelCount == 0) || (PixelStart + PixelCount > Count)) // check for corrupt pixel length
|
|
{
|
|
PixelCount = Count - PixelStart;
|
|
DCMIMGLE_DEBUG("setting number of pixels to be processed (PixelCount) to: " << PixelCount);
|
|
}
|
|
}
|
|
|
|
/** destructor
|
|
*/
|
|
virtual ~DiInputPixelTemplate()
|
|
{
|
|
#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
|
|
/* use a non-throwing delete (if available) */
|
|
operator delete[] (Data, std::nothrow);
|
|
#else
|
|
delete[] Data;
|
|
#endif
|
|
}
|
|
|
|
/** determine minimum and maximum pixel value
|
|
*
|
|
** @return status, true if successful, false otherwise
|
|
*/
|
|
int determineMinMax()
|
|
{
|
|
if (Data != NULL)
|
|
{
|
|
DCMIMGLE_DEBUG("determining minimum and maximum pixel values for input data");
|
|
T2 *p = Data;
|
|
unsigned long i;
|
|
const unsigned long ocnt = OFstatic_cast(unsigned long, getAbsMaxRange());
|
|
Uint8 *lut = NULL;
|
|
if ((sizeof(T2) <= 2) && (Count > 3 * ocnt)) // optimization criteria
|
|
{
|
|
lut = new Uint8[ocnt];
|
|
if (lut != NULL)
|
|
{
|
|
DCMIMGLE_DEBUG("using optimized routine with additional LUT");
|
|
OFBitmanipTemplate<Uint8>::zeroMem(lut, ocnt);
|
|
Uint8 *q = lut - OFstatic_cast(T2, getAbsMinimum());
|
|
for (i = Count; i != 0; --i) // fill lookup table
|
|
*(q + *(p++)) = 1;
|
|
q = lut;
|
|
for (i = 0; i < ocnt; ++i) // search for minimum
|
|
{
|
|
if (*(q++) != 0)
|
|
{
|
|
MinValue[0] = OFstatic_cast(T2, OFstatic_cast(double, i) + getAbsMinimum());
|
|
break;
|
|
}
|
|
}
|
|
q = lut + ocnt;
|
|
for (i = ocnt; i != 0; --i) // search for maximum
|
|
{
|
|
if (*(--q) != 0)
|
|
{
|
|
MaxValue[0] = OFstatic_cast(T2, OFstatic_cast(double, i - 1) + getAbsMinimum());
|
|
break;
|
|
}
|
|
}
|
|
if (Count >= PixelCount) // use global min/max value
|
|
{
|
|
MinValue[1] = MinValue[0];
|
|
MaxValue[1] = MaxValue[0];
|
|
} else { // calculate min/max for selected range
|
|
OFBitmanipTemplate<Uint8>::zeroMem(lut, ocnt);
|
|
p = Data + PixelStart;
|
|
q = lut - OFstatic_cast(T2, getAbsMinimum());
|
|
for (i = PixelCount; i != 0; --i) // fill lookup table
|
|
*(q + *(p++)) = 1;
|
|
q = lut;
|
|
for (i = 0; i < ocnt; ++i) // search for minimum
|
|
{
|
|
if (*(q++) != 0)
|
|
{
|
|
MinValue[1] = OFstatic_cast(T2, OFstatic_cast(double, i) + getAbsMinimum());
|
|
break;
|
|
}
|
|
}
|
|
q = lut + ocnt;
|
|
for (i = ocnt; i != 0; --i) // search for maximum
|
|
{
|
|
if (*(--q) != 0)
|
|
{
|
|
MaxValue[1] = OFstatic_cast(T2, OFstatic_cast(double, i - 1) + getAbsMinimum());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (lut == NULL) // use conventional method
|
|
{
|
|
T2 value = *p;
|
|
MinValue[0] = value;
|
|
MaxValue[0] = value;
|
|
for (i = Count; i > 1; --i)
|
|
{
|
|
value = *(++p);
|
|
if (value < MinValue[0])
|
|
MinValue[0] = value;
|
|
else if (value > MaxValue[0])
|
|
MaxValue[0] = value;
|
|
}
|
|
if (Count <= PixelCount) // use global min/max value
|
|
{
|
|
MinValue[1] = MinValue[0];
|
|
MaxValue[1] = MaxValue[0];
|
|
} else { // calculate min/max for selected range
|
|
p = Data + PixelStart;
|
|
value = *p;
|
|
MinValue[1] = value;
|
|
MaxValue[1] = value;
|
|
for (i = PixelCount; i > 1; --i)
|
|
{
|
|
value = *(++p);
|
|
if (value < MinValue[1])
|
|
MinValue[1] = value;
|
|
else if (value > MaxValue[1])
|
|
MaxValue[1] = value;
|
|
}
|
|
}
|
|
}
|
|
delete[] lut;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/** get pixel representation
|
|
*
|
|
** @return pixel representation
|
|
*/
|
|
inline EP_Representation getRepresentation() const
|
|
{
|
|
return DiPixelRepresentationTemplate<T2>::getRepresentation();
|
|
}
|
|
|
|
/** get pointer to input pixel data
|
|
*
|
|
** @return pointer to input pixel data
|
|
*/
|
|
inline const void *getData() const
|
|
{
|
|
return OFstatic_cast(const void *, Data);
|
|
}
|
|
|
|
/** get reference to pointer to input pixel data
|
|
*
|
|
** @return reference to pointer to input pixel data
|
|
*/
|
|
virtual void *getDataPtr()
|
|
{
|
|
return OFstatic_cast(void *, Data);
|
|
}
|
|
|
|
/** remove reference to (internally handled) pixel data
|
|
*/
|
|
inline void removeDataReference()
|
|
{
|
|
Data = NULL;
|
|
}
|
|
|
|
/** get minimum pixel value
|
|
*
|
|
** @param idx specifies whether to return the global minimum (0) or
|
|
* the minimum of the selected pixel range (1, see PixelStart/Range)
|
|
*
|
|
** @return minimum pixel value
|
|
*/
|
|
inline double getMinValue(const int idx) const
|
|
{
|
|
return (idx == 0) ? OFstatic_cast(double, MinValue[0]) : OFstatic_cast(double, MinValue[1]);
|
|
}
|
|
|
|
/** get maximum pixel value
|
|
*
|
|
** @param idx specifies whether to return the global maximum (0) or
|
|
* the maximum of the selected pixel range (1, see PixelStart/Range)
|
|
*
|
|
** @return maximum pixel value
|
|
*/
|
|
inline double getMaxValue(const int idx) const
|
|
{
|
|
return (idx == 0) ? OFstatic_cast(double, MaxValue[0]) : OFstatic_cast(double, MaxValue[1]);
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
/** convert pixel data from DICOM dataset to input representation
|
|
*
|
|
** @param document pointer to DICOM image object
|
|
* @param bitsAllocated number of bits allocated for each pixel
|
|
* @param bitsStored number of bits stored for each pixel
|
|
* @param highBit position of high bit within bits allocated
|
|
* @param fileCache pointer to file cache object used for partial read
|
|
* @param fragment current pixel item fragment (for encapsulated pixel data)
|
|
*/
|
|
void convert(const DiDocument *document,
|
|
const Uint16 bitsAllocated,
|
|
const Uint16 bitsStored,
|
|
const Uint16 highBit,
|
|
DcmFileCache *fileCache,
|
|
Uint32 &fragment)
|
|
{
|
|
T1 *pixel = NULL;
|
|
OFBool deletePixel = OFFalse;
|
|
Uint32 lengthBytes = 0;
|
|
DcmPixelData *pixelData = document->getPixelData();
|
|
const Uint16 bitsof_T1 = bitsof(T1);
|
|
const Uint16 bitsof_T2 = bitsof(T2);
|
|
const OFBool uncompressed = pixelData->canWriteXfer(EXS_LittleEndianExplicit, EXS_Unknown);
|
|
/* check whether to use partial read */
|
|
if ((document->getFlags() & CIF_UsePartialAccessToPixelData) && (PixelCount > 0) && (bitsAllocated % 8 == 0))
|
|
{
|
|
/* Bits Allocated is always a multiple of 8 (see above), same for bits of T1 */
|
|
const Uint32 byteFactor = bitsAllocated / 8;
|
|
const Uint32 bytes_T1 = bitsof_T1 / 8;
|
|
const Uint32 count_T1 = (byteFactor == bytes_T1) ? PixelCount : (PixelCount * byteFactor + bytes_T1 - 1) / bytes_T1;
|
|
#ifdef DEBUG
|
|
DCMIMGLE_TRACE("PixelCount: " << PixelCount << ", byteFactor: " << byteFactor << ", bytes_T1: " << bytes_T1 << ", count_T1: " << count_T1);
|
|
#endif
|
|
/* allocate temporary buffer, even number of bytes required for getUncompressedFrame() */
|
|
const Uint32 extraByte = ((sizeof(T1) == 1) && (count_T1 & 1)) ? 1 : 0;
|
|
#ifdef HAVE_STD__NOTHROW
|
|
/* use a non-throwing new here (if available) because the allocated buffer can be huge */
|
|
pixel = new (std::nothrow) T1[count_T1 + extraByte];
|
|
#else
|
|
/* make sure that the pointer is set to NULL in case of error */
|
|
try
|
|
{
|
|
pixel = new T1[count_T1 + extraByte];
|
|
}
|
|
catch (STD_NAMESPACE bad_alloc const &)
|
|
{
|
|
pixel = NULL;
|
|
}
|
|
#endif
|
|
if (pixel != NULL)
|
|
{
|
|
if (uncompressed)
|
|
{
|
|
DCMIMGLE_DEBUG("using partial read access to uncompressed pixel data");
|
|
const Uint32 offset = PixelStart * byteFactor;
|
|
const Uint32 bufSize = PixelCount * byteFactor;
|
|
const OFCondition status = pixelData->getPartialValue(pixel, offset, bufSize, fileCache);
|
|
if (status.good())
|
|
{
|
|
PixelStart = 0;
|
|
lengthBytes = bufSize;
|
|
} else {
|
|
DCMIMGLE_ERROR("can't access partial value from byte offset " << offset << " to "
|
|
<< (offset + bufSize - 1) << ": " << status.text());
|
|
}
|
|
} else {
|
|
DCMIMGLE_DEBUG("using partial read access to compressed pixel data");
|
|
OFCondition status = EC_IllegalCall;
|
|
OFString decompressedColorModel;
|
|
const Uint32 fsize = FrameSize * byteFactor;
|
|
for (Uint32 frame = 0; frame < NumberOfFrames; ++frame)
|
|
{
|
|
/* make sure that the buffer always has an even number of bytes as required for getUncompressedFrame() */
|
|
const Uint32 bufSize = (fsize & 1) ? fsize + 1 : fsize;
|
|
status = pixelData->getUncompressedFrame(document->getDataset(), FirstFrame + frame, fragment,
|
|
OFreinterpret_cast(Uint8 *, pixel) + lengthBytes, bufSize, decompressedColorModel, fileCache);
|
|
if (status.good())
|
|
{
|
|
DCMIMGLE_TRACE("successfully decompressed frame " << FirstFrame + frame);
|
|
lengthBytes += fsize;
|
|
} else {
|
|
DCMIMGLE_ERROR("can't decompress frame " << FirstFrame + frame << ": " << status.text());
|
|
break;
|
|
}
|
|
}
|
|
if (status.good())
|
|
PixelStart = 0;
|
|
/* check whether color model changed during decompression */
|
|
if (!decompressedColorModel.empty() && (decompressedColorModel != document->getPhotometricInterpretation()))
|
|
{
|
|
DCMIMGLE_WARN("Photometric Interpretation of decompressed pixel data deviates from original image: "
|
|
<< decompressedColorModel);
|
|
}
|
|
}
|
|
deletePixel = OFTrue;
|
|
} else
|
|
DCMIMGLE_DEBUG("cannot allocate memory buffer for 'pixel' in DiInputPixelTemplate::convert()");
|
|
} else {
|
|
DCMIMGLE_DEBUG("reading uncompressed pixel data completely into memory");
|
|
/* always access complete pixel data */
|
|
lengthBytes = getPixelData(pixelData, pixel);
|
|
}
|
|
if ((pixel != NULL) && (lengthBytes > 0))
|
|
{
|
|
const Uint32 length_T1 = lengthBytes / sizeof(T1);
|
|
/* need to split 'length' in order to avoid integer overflow for large pixel data */
|
|
const Uint32 length_B1 = lengthBytes / bitsAllocated;
|
|
const Uint32 length_B2 = lengthBytes % bitsAllocated;
|
|
// # old code: Count = ((lengthBytes * 8) + bitsAllocated - 1) / bitsAllocated;
|
|
Count = 8 * length_B1 + (8 * length_B2 + bitsAllocated - 1) / bitsAllocated;
|
|
unsigned long i;
|
|
#ifdef HAVE_STD__NOTHROW
|
|
/* use a non-throwing new here (if available) because the allocated buffer can be huge */
|
|
Data = new (std::nothrow) T2[Count];
|
|
#else
|
|
/* make sure that the pointer is set to NULL in case of error */
|
|
try
|
|
{
|
|
Data = new T2[Count];
|
|
}
|
|
catch (STD_NAMESPACE bad_alloc const &)
|
|
{
|
|
Data = NULL;
|
|
}
|
|
#endif
|
|
if (Data != NULL)
|
|
{
|
|
DCMIMGLE_TRACE("Input length: " << lengthBytes << " bytes, Pixel count: " << Count
|
|
<< " (" << PixelCount << "), In: " << bitsof_T1 << " bits, Out: " << bitsof_T2
|
|
<< " bits (" << (this->isSigned() ? "signed" : "unsigned") << ")");
|
|
const T1 *p = pixel;
|
|
T2 *q = Data;
|
|
if (bitsof_T1 == bitsAllocated) // case 1: equal 8/16 bit
|
|
{
|
|
if (bitsStored == bitsAllocated)
|
|
{
|
|
DCMIMGLE_DEBUG("convert input pixel data: case 1a (single copy)");
|
|
for (i = Count; i != 0; --i)
|
|
*(q++) = OFstatic_cast(T2, *(p++));
|
|
}
|
|
else /* bitsStored < bitsAllocated */
|
|
{
|
|
T1 mask = 0;
|
|
for (i = 0; i < bitsStored; ++i)
|
|
mask |= OFstatic_cast(T1, 1 << i);
|
|
const T2 sign = 1 << (bitsStored - 1);
|
|
T2 smask = 0;
|
|
for (i = bitsStored; i < bitsof_T2; ++i)
|
|
smask |= OFstatic_cast(T2, 1 << i);
|
|
const Uint16 shift = highBit + 1 - bitsStored;
|
|
if (shift == 0)
|
|
{
|
|
DCMIMGLE_DEBUG("convert input pixel data: case 1b (mask & sign)");
|
|
for (i = length_T1; i != 0; --i)
|
|
*(q++) = expandSign(OFstatic_cast(T2, *(p++) & mask), sign, smask);
|
|
}
|
|
else /* shift > 0 */
|
|
{
|
|
DCMIMGLE_DEBUG("convert input pixel data: case 1c (shift & mask & sign)");
|
|
for (i = length_T1; i != 0; --i)
|
|
*(q++) = expandSign(OFstatic_cast(T2, (*(p++) >> shift) & mask), sign, smask);
|
|
}
|
|
}
|
|
}
|
|
else if ((bitsof_T1 > bitsAllocated) && (bitsof_T1 % bitsAllocated == 0)) // case 2: divisor of 8/16 bit
|
|
{
|
|
const Uint16 times = bitsof_T1 / bitsAllocated;
|
|
T1 mask = 0;
|
|
for (i = 0; i < bitsStored; ++i)
|
|
mask |= OFstatic_cast(T1, 1 << i);
|
|
Uint16 j;
|
|
T1 value;
|
|
if ((bitsStored == bitsAllocated) && (bitsStored == bitsof_T2))
|
|
{
|
|
if (times == 2)
|
|
{
|
|
DCMIMGLE_DEBUG("convert input pixel data: case 2a (simple mask)");
|
|
for (i = length_T1; i != 0; --i, ++p)
|
|
{
|
|
*(q++) = OFstatic_cast(T2, *p & mask);
|
|
*(q++) = OFstatic_cast(T2, *p >> bitsAllocated);
|
|
}
|
|
/* check for additional input pixel (in case of odd length when using partial access) */
|
|
if (length_T1 * 2 /* times */ < lengthBytes)
|
|
{
|
|
DCMIMGLE_TRACE("found trailing pixel at the end of odd-length input data ... copying value");
|
|
*(q++) = OFstatic_cast(T2, *p & mask);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DCMIMGLE_DEBUG("convert input pixel data: case 2b (mask)");
|
|
for (i = length_T1; i != 0; --i)
|
|
{
|
|
value = *(p++);
|
|
for (j = times; j != 0; --j)
|
|
{
|
|
*(q++) = OFstatic_cast(T2, value & mask);
|
|
value >>= bitsAllocated;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DCMIMGLE_DEBUG("convert input pixel data: case 2c (shift & mask & sign)");
|
|
const T2 sign = 1 << (bitsStored - 1);
|
|
T2 smask = 0;
|
|
for (i = bitsStored; i < bitsof_T2; ++i)
|
|
smask |= OFstatic_cast(T2, 1 << i);
|
|
const Uint16 shift = highBit + 1 - bitsStored;
|
|
for (i = length_T1; i != 0; --i)
|
|
{
|
|
value = *(p++) >> shift;
|
|
for (j = times; j != 0; --j)
|
|
{
|
|
*(q++) = expandSign(OFstatic_cast(T2, value & mask), sign, smask);
|
|
value >>= bitsAllocated;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((bitsof_T1 < bitsAllocated) && (bitsAllocated % bitsof_T1 == 0) // case 3: multiplicand of 8/16
|
|
&& (bitsStored == bitsAllocated))
|
|
{
|
|
DCMIMGLE_DEBUG("convert input pixel data: case 3 (multi copy)");
|
|
const Uint16 times = bitsAllocated / bitsof_T1;
|
|
Uint16 j;
|
|
Uint16 shift;
|
|
T2 value;
|
|
for (i = length_T1; i != 0; --i)
|
|
{
|
|
shift = 0;
|
|
value = OFstatic_cast(T2, *(p++));
|
|
for (j = times; j > 1; --j, --i)
|
|
{
|
|
shift += bitsof_T1;
|
|
value |= OFstatic_cast(T2, *(p++)) << shift;
|
|
}
|
|
*(q++) = value;
|
|
}
|
|
}
|
|
else // case 4: anything else
|
|
{
|
|
DCMIMGLE_DEBUG("convert input pixel data: case 4 (general)");
|
|
T2 value = 0;
|
|
Uint16 bits = 0;
|
|
Uint32 skip = highBit + 1 - bitsStored;
|
|
Uint32 times;
|
|
T1 mask[bitsof_T1];
|
|
mask[0] = 1;
|
|
for (i = 1; i < bitsof_T1; ++i)
|
|
mask[i] = (mask[i - 1] << 1) | 1;
|
|
T2 smask = 0;
|
|
for (i = bitsStored; i < bitsof_T2; ++i)
|
|
smask |= OFstatic_cast(T2, 1 << i);
|
|
const T2 sign = 1 << (bitsStored - 1);
|
|
const Uint32 gap = bitsAllocated - bitsStored;
|
|
i = 0;
|
|
while (i < length_T1)
|
|
{
|
|
if (skip < bitsof_T1)
|
|
{
|
|
if (skip + bitsStored - bits < bitsof_T1) // -++- --++
|
|
{
|
|
value |= (OFstatic_cast(T2, (*p >> skip) & mask[bitsStored - bits - 1]) << bits);
|
|
skip += bitsStored - bits + gap;
|
|
bits = bitsStored;
|
|
}
|
|
else // ++-- ++++
|
|
{
|
|
value |= (OFstatic_cast(T2, (*p >> skip) & mask[bitsof_T1 - skip - 1]) << bits);
|
|
bits += bitsof_T1 - OFstatic_cast(Uint16, skip);
|
|
skip = (bits == bitsStored) ? gap : 0;
|
|
++i;
|
|
++p;
|
|
}
|
|
if (bits == bitsStored)
|
|
{
|
|
*(q++) = expandSign(value, sign, smask);
|
|
value = 0;
|
|
bits = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
times = skip / bitsof_T1;
|
|
i += times;
|
|
p += times;
|
|
skip -= times * bitsof_T1;
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
DCMIMGLE_DEBUG("cannot allocate memory buffer for 'Data' in DiInputPixelTemplate::convert()");
|
|
} else {
|
|
/* in case of error, reset pixel count variable */
|
|
Count = 0;
|
|
}
|
|
if (deletePixel)
|
|
{
|
|
/* delete temporary buffer */
|
|
#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
|
|
/* use a non-throwing delete (if available) */
|
|
operator delete[] (pixel, std::nothrow);
|
|
#else
|
|
delete[] pixel;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/// pointer to pixel data
|
|
T2 *Data;
|
|
|
|
/// minimum pixel value ([0] = global, [1] = selected pixel range)
|
|
T2 MinValue[2];
|
|
/// maximum pixel value ([0] = global, [1] = selected pixel range)
|
|
T2 MaxValue[2];
|
|
|
|
// --- declarations to avoid compiler warnings
|
|
|
|
DiInputPixelTemplate(const DiInputPixelTemplate<T1,T2> &);
|
|
DiInputPixelTemplate<T1,T2> &operator=(const DiInputPixelTemplate<T1,T2> &);
|
|
};
|
|
|
|
|
|
#endif
|