// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_ENCODERSTRATEGY #define CHARLS_ENCODERSTRATEGY #include "dcmtk/ofstd/ofmem.h" #include "dcmtk/ofstd/ofbmanip.h" #include "procline.h" #include "decodstr.h" // Implements encoding to stream of bits. In encoding mode JpegLsCodec inherits from EncoderStrategy class EncoderStrategy { public: explicit EncoderStrategy(const JlsParameters& info) : _qdecoder(OFnullptr), _info(info), _processLine(OFnullptr), valcurrent(0), bitpos(0), _isFFWritten(false), _bytesWritten(0) { } virtual ~EncoderStrategy() { } LONG PeekByte(); void OnLineBegin(LONG cpixel, void* ptypeBuffer, LONG pixelStride) { _processLine->NewLineRequested(ptypeBuffer, cpixel, pixelStride); } void OnLineEnd(LONG /*cpixel*/, void* /*ptypeBuffer*/, LONG /*pixelStride*/) { } virtual void SetPresets(const JlsCustomParameters& presets) = 0; virtual size_t EncodeScan(const void* rawData, BYTE **ptr, size_t *size, size_t offset, bool compare) = 0; protected: void Init(BYTE **ptr, size_t *size, size_t offset) { bitpos = 32; valcurrent = 0; _position = ptr; _size = size; _current_offset = offset; } void AppendToBitStream(LONG value, LONG length) { ASSERT(length < 32 && length >= 0); ASSERT((_qdecoder.get() == NULL) || (length == 0 && value == 0) ||( _qdecoder->ReadLongValue(length) == value)); #ifndef NDEBUG if (length < 32) { int mask = (1 << (length)) - 1; ASSERT((value | mask) == mask); } #endif bitpos -= length; if (bitpos >= 0) { valcurrent = valcurrent | (value << bitpos); return; } valcurrent |= value >> -bitpos; Flush(); // A second flush may be required if extra marker-detect bits were needed and not all bits could be written. if (bitpos < 0) { valcurrent |= value >> -bitpos; Flush(); } ASSERT(bitpos >=0); valcurrent |= value << bitpos; } void EndScan() { Flush(); // if a 0xff was written, Flush() will force one unset bit anyway if (_isFFWritten) AppendToBitStream(0, (bitpos - 1) % 8); else AppendToBitStream(0, bitpos % 8); Flush(); ASSERT(bitpos == 0x20); } void Flush() { for (LONG i = 0; i < 4; ++i) { if (bitpos >= 32) break; if (_isFFWritten) { // JPEG-LS requirement (T.87, A.1) to detect markers: after a xFF value a single 0 bit needs to be inserted. write(BYTE(valcurrent >> 25)); valcurrent = valcurrent << 7; bitpos += 7; _isFFWritten = false; } else { write(BYTE(valcurrent >> 24)); _isFFWritten = (*_position)[_current_offset - 1] == 0xFF; valcurrent = valcurrent << 8; bitpos += 8; } } } size_t GetLength() { return _bytesWritten - (bitpos -32)/8; } inlinehint void AppendOnesToBitStream(LONG length) { AppendToBitStream((1 << length) - 1, length); } OFunique_ptr _qdecoder; protected: JlsParameters _info; OFunique_ptr _processLine; private: static BYTE *re_alloc(BYTE *old_ptr, size_t *old_size) { size_t new_size = *old_size * 2; #ifdef HAVE_STD__NOTHROW BYTE *new_ptr = new(std::nothrow) BYTE[new_size]; #else BYTE *new_ptr = new BYTE[new_size]; #endif if (new_ptr == NULL) { throw alloc_fail(); } OFBitmanipTemplate::copyMem(old_ptr, new_ptr, *old_size); delete[] old_ptr; *old_size = new_size; return new_ptr; } void write(BYTE value) { if (_current_offset == *_size) { *_position = re_alloc(*_position, _size); } (*_position)[_current_offset] = value; ++_current_offset; ++_bytesWritten; } unsigned int valcurrent; LONG bitpos; // encoding BYTE **_position; size_t *_size; size_t _current_offset; bool _isFFWritten; size_t _bytesWritten; }; #endif