// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_PROCESSLINE #define CHARLS_PROCESSLINE #include "util.h" #include "publictypes.h" #include #include #include #ifdef _MSC_VER #pragma warning(disable: 4996) // 'function': was declared deprecated also 'std::': Function call with parameters that may be unsafe [VS2012] #endif // TODO: analyze if template code can be improved #ifdef _MSC_VER #pragma warning(disable: 4127) // conditional expression is constant [VS2013] #endif // // This file defines the ProcessLine base class, its derivitives and helper functions. // During coding/decoding, CharLS process one line at a time. The different Processline implementations // convert the uncompressed format to and from the internal format for encoding. // Conversions include color transforms, line interleaved vs sample interleaved, masking out unused bits, // accounting for line padding etc. // This mechanism could be used to encode/decode images as they are received. // class ProcessLine { public: virtual ~ProcessLine() = default; virtual void NewLineDecoded(const void* pSrc, int pixelCount, int sourceStride) = 0; virtual void NewLineRequested(void* pDest, int pixelCount, int destStride) = 0; }; class PostProcesSingleComponent : public ProcessLine { public: PostProcesSingleComponent(void* rawData, const JlsParameters& params, int bytesPerPixel) : _rawData(static_cast(rawData)), _bytesPerPixel(bytesPerPixel), _bytesPerLine(params.stride) { } void NewLineRequested(void* dest, int pixelCount, int /*byteStride*/) override { ::memcpy(dest, _rawData, pixelCount * _bytesPerPixel); _rawData += _bytesPerLine; } void NewLineDecoded(const void* pSrc, int pixelCount, int /*sourceStride*/) override { ::memcpy(_rawData, pSrc, pixelCount * _bytesPerPixel); _rawData += _bytesPerLine; } private: uint8_t* _rawData; int _bytesPerPixel; int _bytesPerLine; }; inline void ByteSwap(unsigned char* data, int count) { if (count & 1) { std::ostringstream message; message << "An odd number of bytes (" << count << ") cannot be swapped."; throw CreateSystemError(charls::ApiResult::InvalidJlsParameters, message.str()); } unsigned int* data32 = reinterpret_cast(data); for(int i = 0; i < count / 4; i++) { unsigned int value = data32[i]; data32[i] = ((value >> 8) & 0x00FF00FF) | ((value & 0x00FF00FF) << 8); } if ((count % 4) != 0) { std::swap(data[count-2], data[count-1]); } } class PostProcesSingleStream : public ProcessLine { public: PostProcesSingleStream(std::basic_streambuf* rawData, const JlsParameters& params, int bytesPerPixel) : _rawData(rawData), _bytesPerPixel(bytesPerPixel), _bytesPerLine(params.stride) { } void NewLineRequested(void* dest, int pixelCount, int /*destStride*/) override { std::size_t bytesToRead = pixelCount * _bytesPerPixel; while (bytesToRead != 0) { std::streamsize bytesRead = _rawData->sgetn(static_cast(dest), bytesToRead); if (bytesRead == 0) throw std::system_error(static_cast(charls::ApiResult::UncompressedBufferTooSmall), CharLSCategoryInstance()); bytesToRead = static_cast(bytesToRead - bytesRead); } if (_bytesPerPixel == 2 ) { ByteSwap(static_cast(dest), 2 * pixelCount); } if (_bytesPerLine - pixelCount * _bytesPerPixel > 0) { _rawData->pubseekoff(std::streamoff(_bytesPerLine - bytesToRead), std::ios_base::cur); } } void NewLineDecoded(const void* pSrc, int pixelCount, int /*sourceStride*/) override { int bytesToWrite = pixelCount * _bytesPerPixel; std::streamsize bytesWritten = _rawData->sputn(static_cast(pSrc), bytesToWrite); if (bytesWritten != bytesToWrite) throw std::system_error(static_cast(charls::ApiResult::UncompressedBufferTooSmall), CharLSCategoryInstance()); } private: std::basic_streambuf* _rawData; int _bytesPerPixel; int _bytesPerLine; }; template void TransformLineToQuad(const SAMPLE* ptypeInput, int32_t pixelStrideIn, Quad* pbyteBuffer, int32_t pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); Quad* ptypeBuffer = pbyteBuffer; for (int x = 0; x < cpixel; ++x) { Quad pixel(transform(ptypeInput[x], ptypeInput[x + pixelStrideIn], ptypeInput[x + 2*pixelStrideIn]),ptypeInput[x + 3*pixelStrideIn]) ; ptypeBuffer[x] = pixel; } } template void TransformQuadToLine(const Quad* pbyteInput, int32_t pixelStrideIn, SAMPLE* ptypeBuffer, int32_t pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); const Quad* ptypeBufferIn = pbyteInput; for (int x = 0; x < cpixel; ++x) { Quad color = ptypeBufferIn[x]; Quad colorTranformed(transform(color.v1, color.v2, color.v3), color.v4); ptypeBuffer[x] = colorTranformed.v1; ptypeBuffer[x + pixelStride] = colorTranformed.v2; ptypeBuffer[x + 2 * pixelStride] = colorTranformed.v3; ptypeBuffer[x + 3 * pixelStride] = colorTranformed.v4; } } template void TransformRgbToBgr(SAMPLE* pDest, int samplesPerPixel, int pixelCount) { for (int i = 0; i < pixelCount; ++i) { std::swap(pDest[0], pDest[2]); pDest += samplesPerPixel; } } template void TransformLine(Triplet* pDest, const Triplet* pSrc, int pixelCount, TRANSFORM& transform) { for (int i = 0; i < pixelCount; ++i) { pDest[i] = transform(pSrc[i].v1, pSrc[i].v2, pSrc[i].v3); } } template void TransformLineToTriplet(const SAMPLE* ptypeInput, int32_t pixelStrideIn, Triplet* pbyteBuffer, int32_t pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); Triplet* ptypeBuffer = pbyteBuffer; for (int x = 0; x < cpixel; ++x) { ptypeBuffer[x] = transform(ptypeInput[x], ptypeInput[x + pixelStrideIn], ptypeInput[x + 2*pixelStrideIn]); } } template void TransformTripletToLine(const Triplet* pbyteInput, int32_t pixelStrideIn, SAMPLE* ptypeBuffer, int32_t pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); const Triplet* ptypeBufferIn = pbyteInput; for (int x = 0; x < cpixel; ++x) { Triplet color = ptypeBufferIn[x]; Triplet colorTranformed = transform(color.v1, color.v2, color.v3); ptypeBuffer[x] = colorTranformed.v1; ptypeBuffer[x + pixelStride] = colorTranformed.v2; ptypeBuffer[x + 2 *pixelStride] = colorTranformed.v3; } } template class ProcessTransformed : public ProcessLine { typedef typename TRANSFORM::SAMPLE SAMPLE; public: ProcessTransformed(ByteStreamInfo rawStream, const JlsParameters& info, TRANSFORM transform) : _params(info), _templine(info.width * info.components), _buffer(info.width * info.components * sizeof(SAMPLE)), _transform(transform), _inverseTransform(transform), _rawPixels(rawStream) { } void NewLineRequested(void* dest, int pixelCount, int destStride) override { if (!_rawPixels.rawStream) { Transform(_rawPixels.rawData, dest, pixelCount, destStride); _rawPixels.rawData += _params.stride; return; } Transform(_rawPixels.rawStream, dest, pixelCount, destStride); } void Transform(std::basic_streambuf* rawStream, void* dest, int pixelCount, int destStride) { std::streamsize bytesToRead = pixelCount * _params.components * sizeof(SAMPLE); while (bytesToRead != 0) { std::streamsize read = rawStream->sgetn(reinterpret_cast(&_buffer[0]), bytesToRead); if (read == 0) { std::ostringstream message; message << "No more bytes available in input buffer, still neededing " << read; throw CreateSystemError(charls::ApiResult::UncompressedBufferTooSmall, message.str()); } bytesToRead -= read; } if (sizeof(SAMPLE) == 2 && _params.colorTransformation == charls::ColorTransformation::BigEndian) { ByteSwap(&_buffer[0], _params.components * sizeof(SAMPLE) * pixelCount); } Transform(&_buffer[0], dest, pixelCount, destStride); } void Transform(const void* source, void* dest, int pixelCount, int destStride) { if (_params.outputBgr) { memcpy(&_templine[0], source, sizeof(Triplet) * pixelCount); TransformRgbToBgr(static_cast(&_templine[0]), _params.components, pixelCount); source = &_templine[0]; } if (_params.components == 3) { if (_params.interleaveMode == charls::InterleaveMode::Sample) { TransformLine(static_cast*>(dest), static_cast*>(source), pixelCount, _transform); } else { TransformTripletToLine(static_cast*>(source), pixelCount, static_cast(dest), destStride, _transform); } } else if (_params.components == 4 && _params.interleaveMode == charls::InterleaveMode::Line) { TransformQuadToLine(static_cast*>(source), pixelCount, static_cast(dest), destStride, _transform); } } void DecodeTransform(const void* pSrc, void* rawData, int pixelCount, int byteStride) { if (_params.components == 3) { if (_params.interleaveMode == charls::InterleaveMode::Sample) { TransformLine(static_cast*>(rawData), static_cast*>(pSrc), pixelCount, _inverseTransform); } else { TransformLineToTriplet(static_cast(pSrc), byteStride, static_cast*>(rawData), pixelCount, _inverseTransform); } } else if (_params.components == 4 && _params.interleaveMode == charls::InterleaveMode::Line) { TransformLineToQuad(static_cast(pSrc), byteStride, static_cast*>(rawData), pixelCount, _inverseTransform); } if (_params.outputBgr) { TransformRgbToBgr(static_cast(rawData), _params.components, pixelCount); } } void NewLineDecoded(const void* pSrc, int pixelCount, int sourceStride) override { if (_rawPixels.rawStream) { std::streamsize bytesToWrite = pixelCount * _params.components * sizeof(SAMPLE); DecodeTransform(pSrc, &_buffer[0], pixelCount, sourceStride); if (sizeof(SAMPLE) == 2 && _params.colorTransformation == charls::ColorTransformation::BigEndian) { ByteSwap(&_buffer[0], _params.components * sizeof(SAMPLE) * pixelCount); } std::streamsize bytesWritten = _rawPixels.rawStream->sputn(reinterpret_cast(&_buffer[0]), bytesToWrite); if (bytesWritten != bytesToWrite) throw std::system_error(static_cast(charls::ApiResult::UncompressedBufferTooSmall), CharLSCategoryInstance()); } else { DecodeTransform(pSrc, _rawPixels.rawData, pixelCount, sourceStride); _rawPixels.rawData += _params.stride; } } private: const JlsParameters& _params; std::vector _templine; std::vector _buffer; TRANSFORM _transform; typename TRANSFORM::INVERSE _inverseTransform; ByteStreamInfo _rawPixels; }; #endif