// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_PROCESSLINE #define CHARLS_PROCESSLINE #include "clrtrans.h" // // 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() {} virtual void NewLineDecoded(const void* pSrc, int pixelCount, int bytesperline) = 0; virtual void NewLineRequested(void* pSrc, int pixelCount, int bytesperline) = 0; }; class PostProcesSingleComponent : public ProcessLine { public: PostProcesSingleComponent(void* pbyteOutput, const JlsParameters& info, int bytesPerPixel) : _pbyteOutput((BYTE*)pbyteOutput), _bytesPerPixel(bytesPerPixel), _bytesPerLine(info.bytesperline) { } void NewLineRequested(void* pDst, int pixelCount, int /*byteStride*/) { OFBitmanipTemplate::copyMem(_pbyteOutput, (BYTE*) pDst, pixelCount * _bytesPerPixel); _pbyteOutput += _bytesPerLine; } void NewLineDecoded(const void* pSrc, int pixelCount, int /*byteStride*/) { OFBitmanipTemplate::copyMem((BYTE*) pSrc, _pbyteOutput, pixelCount * _bytesPerPixel); _pbyteOutput += _bytesPerLine; } private: BYTE* _pbyteOutput; int _bytesPerPixel; int _bytesPerLine; }; template void TransformLineToQuad(const SAMPLE* ptypeInput, LONG pixelStrideIn, Quad* pbyteBuffer, LONG pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); Quad* ptypeBuffer = (Quad*)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, LONG pixelStrideIn, SAMPLE* ptypeBuffer, LONG pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); const Quad* ptypeBufferIn = (Quad*)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) { SAMPLE tmp = pDest[0]; pDest[0] = pDest[2]; pDest[2] = tmp; 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, LONG pixelStrideIn, Triplet* pbyteBuffer, LONG pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); Triplet* ptypeBuffer = (Triplet*)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, LONG pixelStrideIn, SAMPLE* ptypeBuffer, LONG pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); const Triplet* ptypeBufferIn = (Triplet*)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; ProcessTransformed(const ProcessTransformed&) {} public: ProcessTransformed(void* pbyteOutput, const JlsParameters& info, TRANSFORM transform) : _pbyteOutput((BYTE*)pbyteOutput), _info(info), _templine(info.width * info.components), _transform(transform), _inverseTransform(transform) { // ASSERT(_info.components == sizeof(TRIPLET)/sizeof(TRIPLET::SAMPLE)); } void NewLineRequested(void* pDst, int pixelCount, int stride) { SAMPLE* pLine = (SAMPLE*)_pbyteOutput; if (_info.outputBgr) { pLine = &_templine[0]; memcpy(pLine, _pbyteOutput, sizeof(Triplet)*pixelCount); TransformRgbToBgr(pLine, _info.components, pixelCount); } if (_info.components == 3) { if (_info.ilv == ILV_SAMPLE) { TransformLine((Triplet*)pDst, (const Triplet*)pLine, pixelCount, _transform); } else { TransformTripletToLine((const Triplet*)pLine, pixelCount, (SAMPLE*)pDst, stride, _transform); } } else if (_info.components == 4 && _info.ilv == ILV_LINE) { TransformQuadToLine((const Quad*)pLine, pixelCount, (SAMPLE*)pDst, stride, _transform); } _pbyteOutput += _info.bytesperline; } void NewLineDecoded(const void* pSrc, int pixelCount, int byteStride) { if (_info.components == 3) { if (_info.ilv == ILV_SAMPLE) { TransformLine((Triplet*)_pbyteOutput, (const Triplet*)pSrc, pixelCount, _inverseTransform); } else { TransformLineToTriplet((const SAMPLE*)pSrc, byteStride, (Triplet*)_pbyteOutput, pixelCount, _inverseTransform); } } else if (_info.components == 4 && _info.ilv == ILV_LINE) { TransformLineToQuad((const SAMPLE*)pSrc, byteStride, (Quad*)_pbyteOutput, pixelCount, _inverseTransform); } if (_info.outputBgr) { TransformRgbToBgr(_pbyteOutput, _info.components, pixelCount); } _pbyteOutput += _info.bytesperline; } private: BYTE* _pbyteOutput; const JlsParameters& _info; OFVector _templine; TRANSFORM _transform; typename TRANSFORM::INVERSE _inverseTransform; }; #endif