// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_SCAN #define CHARLS_SCAN #include "lookuptable.h" #include "contextrunmode.h" #include "context.h" #include "colortransform.h" #include // This file contains the code for handling a "scan". Usually an image is encoded as a single scan. #ifdef _MSC_VER #pragma warning (disable: 4127) // conditional expression is constant (caused by some template methods that are not fully specialized) [VS2013] #endif extern CTable decodingTables[16]; extern std::vector rgquant8Ll; extern std::vector rgquant10Ll; extern std::vector rgquant12Ll; extern std::vector rgquant16Ll; inlinehint int32_t ApplySign(int32_t i, int32_t sign) { return (sign ^ i) - sign; } // Two alternatives for GetPredictedValue() (second is slightly faster due to reduced branching) #if 0 inlinehint int32_t GetPredictedValue(int32_t Ra, int32_t Rb, int32_t Rc) { if (Ra < Rb) { if (Rc < Ra) return Rb; if (Rc > Rb) return Ra; } else { if (Rc < Rb) return Ra; if (Rc > Ra) return Rb; } return Ra + Rb - Rc; } #else inlinehint int32_t GetPredictedValue(int32_t Ra, int32_t Rb, int32_t Rc) { // sign trick reduces the number of if statements (branches) int32_t sgn = BitWiseSign(Rb - Ra); // is Ra between Rc and Rb? if ((sgn ^ (Rc - Ra)) < 0) { return Rb; } else if ((sgn ^ (Rb - Rc)) < 0) { return Ra; } // default case, valid if Rc element of [Ra,Rb] return Ra + Rb - Rc; } #endif inlinehint int32_t UnMapErrVal(int32_t mappedError) { //int32_t sign = ~((mappedError & 1) - 1); int32_t sign = int32_t(mappedError << (INT32_BITCOUNT-1)) >> (INT32_BITCOUNT-1); return sign ^ (mappedError >> 1); } inlinehint int32_t GetMappedErrVal(int32_t Errval) { int32_t mappedError = (Errval >> (INT32_BITCOUNT-2)) ^ (2 * Errval); return mappedError; } inlinehint int32_t ComputeContextID(int32_t Q1, int32_t Q2, int32_t Q3) { return (Q1*9 + Q2)*9 + Q3; } template class JlsCodec : public STRATEGY { public: typedef typename TRAITS::PIXEL PIXEL; typedef typename TRAITS::SAMPLE SAMPLE; JlsCodec(const TRAITS& inTraits, const JlsParameters& params) : STRATEGY(params), traits(inTraits), _rect(), _width(params.width), T1(0), T2(0), T3(0), _RUNindex(0), _previousLine(), _currentLine(), _pquant(nullptr), _bCompare(false) { if (Info().interleaveMode == InterleaveMode::None) { Info().components = 1; } } void SetPresets(const JlsCustomParameters& presets) override { JlsCustomParameters presetDefault = ComputeDefault(traits.MAXVAL, traits.NEAR); InitParams(presets.T1 != 0 ? presets.T1 : presetDefault.T1, presets.T2 != 0 ? presets.T2 : presetDefault.T2, presets.T3 != 0 ? presets.T3 : presetDefault.T3, presets.RESET != 0 ? presets.RESET : presetDefault.RESET); } bool IsInterleaved() { if (Info().interleaveMode == InterleaveMode::None) return false; if (Info().components == 1) return false; return true; } JlsParameters& Info() { return STRATEGY::_params; } signed char QuantizeGratientOrg(int32_t Di); inlinehint int32_t QuantizeGratient(int32_t Di) { ASSERT(QuantizeGratientOrg(Di) == *(_pquant + Di)); return *(_pquant + Di); } void InitQuantizationLUT(); int32_t DecodeValue(int32_t k, int32_t limit, int32_t qbpp); inlinehint void EncodeMappedValue(int32_t k, int32_t mappedError, int32_t limit); void IncrementRunIndex() { _RUNindex = MIN(31,_RUNindex + 1); } void DecrementRunIndex() { _RUNindex = MAX(0,_RUNindex - 1); } int32_t DecodeRIError(CContextRunMode& ctx); Triplet DecodeRIPixel(Triplet Ra, Triplet Rb); SAMPLE DecodeRIPixel(int32_t Ra, int32_t Rb); int32_t DecodeRunPixels(PIXEL Ra, PIXEL* ptype, int32_t cpixelMac); int32_t DoRunMode(int32_t index, DecoderStrategy*); void EncodeRIError(CContextRunMode& ctx, int32_t Errval); SAMPLE EncodeRIPixel(int32_t x, int32_t Ra, int32_t Rb); Triplet EncodeRIPixel(Triplet x, Triplet Ra, Triplet Rb); void EncodeRunPixels(int32_t runLength, bool bEndofline); int32_t DoRunMode(int32_t index, EncoderStrategy*); inlinehint SAMPLE DoRegular(int32_t Qs, int32_t, int32_t pred, DecoderStrategy*); inlinehint SAMPLE DoRegular(int32_t Qs, int32_t x, int32_t pred, EncoderStrategy*); void DoLine(SAMPLE* pdummy); void DoLine(Triplet* pdummy); void DoScan(); public: ProcessLine* CreateProcess(ByteStreamInfo rawStreamInfo) override; void InitDefault(); void InitParams(int32_t t1, int32_t t2, int32_t t3, int32_t nReset); #if defined(__clang__) && (__clang_major__ > 6) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winconsistent-missing-override" #endif size_t EncodeScan(std::unique_ptr rawData, ByteStreamInfo& compressedData, void* pvoidCompare); void DecodeScan(std::unique_ptr rawData, const JlsRect& size, ByteStreamInfo& compressedData, bool bCompare); #if defined(__clang__) && (__clang_major__ > 6) #pragma clang diagnostic pop #endif protected: // codec parameters TRAITS traits; JlsRect _rect; int _width; int32_t T1; int32_t T2; int32_t T3; // compression context JlsContext _contexts[365]; CContextRunMode _contextRunmode[2]; int32_t _RUNindex; PIXEL* _previousLine; // previous line ptr PIXEL* _currentLine; // current line ptr // quantization lookup table signed char* _pquant; std::vector _rgquant; // debugging bool _bCompare; }; // Encode/decode a single sample. Performancewise the #1 important functions template typename TRAITS::SAMPLE JlsCodec::DoRegular(int32_t Qs, int32_t, int32_t pred, DecoderStrategy*) { int32_t sign = BitWiseSign(Qs); JlsContext& ctx = _contexts[ApplySign(Qs, sign)]; int32_t k = ctx.GetGolomb(); int32_t Px = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign)); int32_t ErrVal; const Code& code = decodingTables[k].Get(STRATEGY::PeekByte()); if (code.GetLength() != 0) { STRATEGY::Skip(code.GetLength()); ErrVal = code.GetValue(); ASSERT(std::abs(ErrVal) < 65535); } else { ErrVal = UnMapErrVal(DecodeValue(k, traits.LIMIT, traits.qbpp)); if (std::abs(ErrVal) > 65535) throw std::system_error(static_cast(charls::ApiResult::InvalidCompressedData), CharLSCategoryInstance()); } if (k == 0) { ErrVal = ErrVal ^ ctx.GetErrorCorrection(traits.NEAR); } ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); ErrVal = ApplySign(ErrVal, sign); return traits.ComputeReconstructedSample(Px, ErrVal); } template typename TRAITS::SAMPLE JlsCodec::DoRegular(int32_t Qs, int32_t x, int32_t pred, EncoderStrategy*) { int32_t sign = BitWiseSign(Qs); JlsContext& ctx = _contexts[ApplySign(Qs, sign)]; int32_t k = ctx.GetGolomb(); int32_t Px = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign)); int32_t ErrVal = traits.ComputeErrVal(ApplySign(x - Px, sign)); EncodeMappedValue(k, GetMappedErrVal(ctx.GetErrorCorrection(k | traits.NEAR) ^ ErrVal), traits.LIMIT); ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); ASSERT(traits.IsNear(traits.ComputeReconstructedSample(Px, ApplySign(ErrVal, sign)), x)); return static_cast(traits.ComputeReconstructedSample(Px, ApplySign(ErrVal, sign))); } // Functions to build tables used to decode short golomb codes. inlinehint std::pair CreateEncodedValue(int32_t k, int32_t mappedError) { int32_t highbits = mappedError >> k; return std::make_pair(highbits + k + 1, (int32_t(1) << k) | (mappedError & ((int32_t(1) << k) - 1))); } inline CTable InitTable(int32_t k) { CTable table; for (short nerr = 0; ; nerr++) { // Q is not used when k != 0 int32_t merrval = GetMappedErrVal(nerr);//, k, -1); std::pair paircode = CreateEncodedValue(k, merrval); if (paircode.first > CTable::cbit) break; Code code = Code( nerr, short(paircode.first) ); table.AddEntry(uint8_t(paircode.second), code); } for (short nerr = -1; ; nerr--) { // Q is not used when k != 0 int32_t merrval = GetMappedErrVal(nerr);//, k, -1); std::pair paircode = CreateEncodedValue(k, merrval); if (paircode.first > CTable::cbit) break; Code code = Code(nerr, short(paircode.first)); table.AddEntry(uint8_t(paircode.second), code); } return table; } // Encoding/decoding of golomb codes template int32_t JlsCodec::DecodeValue(int32_t k, int32_t limit, int32_t qbpp) { int32_t highbits = STRATEGY::ReadHighbits(); if (highbits >= limit - (qbpp + 1)) return STRATEGY::ReadValue(qbpp) + 1; if (k == 0) return highbits; return (highbits << k) + STRATEGY::ReadValue(k); } template inlinehint void JlsCodec::EncodeMappedValue(int32_t k, int32_t mappedError, int32_t limit) { int32_t highbits = mappedError >> k; if (highbits < limit - traits.qbpp - 1) { if (highbits + 1 > 31) { STRATEGY::AppendToBitStream(0, highbits / 2); highbits = highbits - highbits / 2; } STRATEGY::AppendToBitStream(1, highbits + 1); STRATEGY::AppendToBitStream((mappedError & ((1 << k) - 1)), k); return; } if (limit - traits.qbpp > 31) { STRATEGY::AppendToBitStream(0, 31); STRATEGY::AppendToBitStream(1, limit - traits.qbpp - 31); } else { STRATEGY::AppendToBitStream(1, limit - traits.qbpp); } STRATEGY::AppendToBitStream((mappedError - 1) & ((1 << traits.qbpp) - 1), traits.qbpp); } // Disable the Microsoft Static Analyzer warning: Potential comparison of a constant with another constant. (false warning, triggered by template construction) #ifdef _PREFAST_ #pragma warning(push) #pragma warning(disable:6326) #endif // Sets up a lookup table to "Quantize" sample difference. template void JlsCodec::InitQuantizationLUT() { // for lossless mode with default parameters, we have precomputed the luts for bitcounts 8, 10, 12 and 16. if (traits.NEAR == 0 && traits.MAXVAL == (1 << traits.bpp) - 1) { JlsCustomParameters presets = ComputeDefault(traits.MAXVAL, traits.NEAR); if (presets.T1 == T1 && presets.T2 == T2 && presets.T3 == T3) { if (traits.bpp == 8) { _pquant = &rgquant8Ll[rgquant8Ll.size() / 2]; return; } if (traits.bpp == 10) { _pquant = &rgquant10Ll[rgquant10Ll.size() / 2]; return; } if (traits.bpp == 12) { _pquant = &rgquant12Ll[rgquant12Ll.size() / 2]; return; } if (traits.bpp == 16) { _pquant = &rgquant16Ll[rgquant16Ll.size() / 2]; return; } } } int32_t RANGE = 1 << traits.bpp; _rgquant.resize(RANGE * 2); _pquant = &_rgquant[RANGE]; for (int32_t i = -RANGE; i < RANGE; ++i) { _pquant[i] = QuantizeGratientOrg(i); } } #ifdef _PREFAST_ #pragma warning(pop) #endif template signed char JlsCodec::QuantizeGratientOrg(int32_t Di) { if (Di <= -T3) return -4; if (Di <= -T2) return -3; if (Di <= -T1) return -2; if (Di < -traits.NEAR) return -1; if (Di <= traits.NEAR) return 0; if (Di < T1) return 1; if (Di < T2) return 2; if (Di < T3) return 3; return 4; } // RI = Run interruption: functions that handle the sample terminating a run. template int32_t JlsCodec::DecodeRIError(CContextRunMode& ctx) { int32_t k = ctx.GetGolomb(); int32_t EMErrval = DecodeValue(k, traits.LIMIT - J[_RUNindex]-1, traits.qbpp); int32_t Errval = ctx.ComputeErrVal(EMErrval + ctx._nRItype, k); ctx.UpdateVariables(Errval, EMErrval); return Errval; } template void JlsCodec::EncodeRIError(CContextRunMode& ctx, int32_t Errval) { int32_t k = ctx.GetGolomb(); bool map = ctx.ComputeMap(Errval, k); int32_t EMErrval = 2 * std::abs(Errval) - ctx._nRItype - int32_t(map); ASSERT(Errval == ctx.ComputeErrVal(EMErrval + ctx._nRItype, k)); EncodeMappedValue(k, EMErrval, traits.LIMIT-J[_RUNindex]-1); ctx.UpdateVariables(Errval, EMErrval); } template Triplet JlsCodec::DecodeRIPixel(Triplet Ra, Triplet Rb) { int32_t Errval1 = DecodeRIError(_contextRunmode[0]); int32_t Errval2 = DecodeRIError(_contextRunmode[0]); int32_t Errval3 = DecodeRIError(_contextRunmode[0]); return Triplet(traits.ComputeReconstructedSample(Rb.v1, Errval1 * Sign(Rb.v1 - Ra.v1)), traits.ComputeReconstructedSample(Rb.v2, Errval2 * Sign(Rb.v2 - Ra.v2)), traits.ComputeReconstructedSample(Rb.v3, Errval3 * Sign(Rb.v3 - Ra.v3))); } template Triplet JlsCodec::EncodeRIPixel(Triplet x, Triplet Ra, Triplet Rb) { int32_t errval1 = traits.ComputeErrVal(Sign(Rb.v1 - Ra.v1) * (x.v1 - Rb.v1)); EncodeRIError(_contextRunmode[0], errval1); int32_t errval2 = traits.ComputeErrVal(Sign(Rb.v2 - Ra.v2) * (x.v2 - Rb.v2)); EncodeRIError(_contextRunmode[0], errval2); int32_t errval3 = traits.ComputeErrVal(Sign(Rb.v3 - Ra.v3) * (x.v3 - Rb.v3)); EncodeRIError(_contextRunmode[0], errval3); return Triplet(traits.ComputeReconstructedSample(Rb.v1, errval1 * Sign(Rb.v1 - Ra.v1)), traits.ComputeReconstructedSample(Rb.v2, errval2 * Sign(Rb.v2 - Ra.v2)), traits.ComputeReconstructedSample(Rb.v3, errval3 * Sign(Rb.v3 - Ra.v3))); } template typename TRAITS::SAMPLE JlsCodec::DecodeRIPixel(int32_t Ra, int32_t Rb) { if (std::abs(Ra - Rb) <= traits.NEAR) { int32_t ErrVal = DecodeRIError(_contextRunmode[1]); return static_cast(traits.ComputeReconstructedSample(Ra, ErrVal)); } else { int32_t ErrVal = DecodeRIError(_contextRunmode[0]); return static_cast(traits.ComputeReconstructedSample(Rb, ErrVal * Sign(Rb - Ra))); } } template typename TRAITS::SAMPLE JlsCodec::EncodeRIPixel(int32_t x, int32_t Ra, int32_t Rb) { if (std::abs(Ra - Rb) <= traits.NEAR) { int32_t ErrVal = traits.ComputeErrVal(x - Ra); EncodeRIError(_contextRunmode[1], ErrVal); return static_cast(traits.ComputeReconstructedSample(Ra, ErrVal)); } else { int32_t ErrVal = traits.ComputeErrVal((x - Rb) * Sign(Rb - Ra)); EncodeRIError(_contextRunmode[0], ErrVal); return static_cast(traits.ComputeReconstructedSample(Rb, ErrVal * Sign(Rb - Ra))); } } // RunMode: Functions that handle run-length encoding template void JlsCodec::EncodeRunPixels(int32_t runLength, bool endOfLine) { while (runLength >= int32_t(1 << J[_RUNindex])) { STRATEGY::AppendOnesToBitStream(1); runLength = runLength - int32_t(1 << J[_RUNindex]); IncrementRunIndex(); } if (endOfLine) { if (runLength != 0) { STRATEGY::AppendOnesToBitStream(1); } } else { STRATEGY::AppendToBitStream(runLength, J[_RUNindex] + 1); // leading 0 + actual remaining length } } template int32_t JlsCodec::DecodeRunPixels(PIXEL Ra, PIXEL* startPos, int32_t cpixelMac) { int32_t index = 0; while (STRATEGY::ReadBit()) { int count = MIN(1 << J[_RUNindex], int(cpixelMac - index)); index += count; ASSERT(index <= cpixelMac); if (count == (1 << J[_RUNindex])) { IncrementRunIndex(); } if (index == cpixelMac) break; } if (index != cpixelMac) { // incomplete run. index += (J[_RUNindex] > 0) ? STRATEGY::ReadValue(J[_RUNindex]) : 0; } if (index > cpixelMac) throw std::system_error(static_cast(charls::ApiResult::InvalidCompressedData), CharLSCategoryInstance()); for (int32_t i = 0; i < index; ++i) { startPos[i] = Ra; } return index; } template int32_t JlsCodec::DoRunMode(int32_t index, EncoderStrategy*) { int32_t ctypeRem = _width - index; PIXEL* ptypeCurX = _currentLine + index; PIXEL* ptypePrevX = _previousLine + index; PIXEL Ra = ptypeCurX[-1]; int32_t runLength = 0; while (traits.IsNear(ptypeCurX[runLength],Ra)) { ptypeCurX[runLength] = Ra; runLength++; if (runLength == ctypeRem) break; } EncodeRunPixels(runLength, runLength == ctypeRem); if (runLength == ctypeRem) return runLength; ptypeCurX[runLength] = EncodeRIPixel(ptypeCurX[runLength], Ra, ptypePrevX[runLength]); DecrementRunIndex(); return runLength + 1; } template int32_t JlsCodec::DoRunMode(int32_t startIndex, DecoderStrategy*) { PIXEL Ra = _currentLine[startIndex-1]; int32_t runLength = DecodeRunPixels(Ra, _currentLine + startIndex, _width - startIndex); int32_t endIndex = startIndex + runLength; if (endIndex == _width) return endIndex - startIndex; // run interruption PIXEL Rb = _previousLine[endIndex]; _currentLine[endIndex] = DecodeRIPixel(Ra, Rb); DecrementRunIndex(); return endIndex - startIndex + 1; } // DoLine: Encodes/Decodes a scanline of samples template void JlsCodec::DoLine(SAMPLE*) { int32_t index = 0; int32_t Rb = _previousLine[index-1]; int32_t Rd = _previousLine[index]; while(index < _width) { int32_t Ra = _currentLine[index -1]; int32_t Rc = Rb; Rb = Rd; Rd = _previousLine[index + 1]; int32_t Qs = ComputeContextID(QuantizeGratient(Rd - Rb), QuantizeGratient(Rb - Rc), QuantizeGratient(Rc - Ra)); if (Qs != 0) { _currentLine[index] = DoRegular(Qs, _currentLine[index], GetPredictedValue(Ra, Rb, Rc), static_cast(nullptr)); index++; } else { index += DoRunMode(index, static_cast(nullptr)); Rb = _previousLine[index - 1]; Rd = _previousLine[index]; } } } // DoLine: Encodes/Decodes a scanline of triplets in ILV_SAMPLE mode template void JlsCodec::DoLine(Triplet*) { int32_t index = 0; while(index < _width) { Triplet Ra = _currentLine[index - 1]; Triplet Rc = _previousLine[index - 1]; Triplet Rb = _previousLine[index]; Triplet Rd = _previousLine[index + 1]; int32_t Qs1 = ComputeContextID(QuantizeGratient(Rd.v1 - Rb.v1), QuantizeGratient(Rb.v1 - Rc.v1), QuantizeGratient(Rc.v1 - Ra.v1)); int32_t Qs2 = ComputeContextID(QuantizeGratient(Rd.v2 - Rb.v2), QuantizeGratient(Rb.v2 - Rc.v2), QuantizeGratient(Rc.v2 - Ra.v2)); int32_t Qs3 = ComputeContextID(QuantizeGratient(Rd.v3 - Rb.v3), QuantizeGratient(Rb.v3 - Rc.v3), QuantizeGratient(Rc.v3 - Ra.v3)); if (Qs1 == 0 && Qs2 == 0 && Qs3 == 0) { index += DoRunMode(index, static_cast(nullptr)); } else { Triplet Rx; Rx.v1 = DoRegular(Qs1, _currentLine[index].v1, GetPredictedValue(Ra.v1, Rb.v1, Rc.v1), static_cast(nullptr)); Rx.v2 = DoRegular(Qs2, _currentLine[index].v2, GetPredictedValue(Ra.v2, Rb.v2, Rc.v2), static_cast(nullptr)); Rx.v3 = DoRegular(Qs3, _currentLine[index].v3, GetPredictedValue(Ra.v3, Rb.v3, Rc.v3), static_cast(nullptr)); _currentLine[index] = Rx; index++; } } } // DoScan: Encodes or decodes a scan. // In ILV_SAMPLE mode, multiple components are handled in DoLine // In ILV_LINE mode, a call do DoLine is made for every component // In ILV_NONE mode, DoScan is called for each component template void JlsCodec::DoScan() { int32_t pixelstride = _width + 4; int components = Info().interleaveMode == charls::InterleaveMode::Line ? Info().components : 1; std::vector vectmp(2 * components * pixelstride); std::vector rgRUNindex(components); for (int32_t line = 0; line < Info().height; ++line) { _previousLine = &vectmp[1]; _currentLine = &vectmp[1 + components * pixelstride]; if ((line & 1) == 1) { std::swap(_previousLine, _currentLine); } STRATEGY::OnLineBegin(_width, _currentLine, pixelstride); for (int component = 0; component < components; ++component) { _RUNindex = rgRUNindex[component]; // initialize edge pixels used for prediction _previousLine[_width] = _previousLine[_width - 1]; _currentLine[-1] = _previousLine[0]; DoLine(static_cast(nullptr)); // dummy arg for overload resolution rgRUNindex[component] = _RUNindex; _previousLine += pixelstride; _currentLine += pixelstride; } if (_rect.Y <= line && line < _rect.Y + _rect.Height) { STRATEGY::OnLineEnd(_rect.Width, _currentLine + _rect.X - (components * pixelstride), pixelstride); } } STRATEGY::EndScan(); } // Factory function for ProcessLine objects to copy/transform unencoded pixels to/from our scanline buffers. template ProcessLine* JlsCodec::CreateProcess(ByteStreamInfo info) { if (!IsInterleaved()) { return info.rawData ? static_cast(new PostProcesSingleComponent(info.rawData, Info(), sizeof(typename TRAITS::PIXEL))) : static_cast(new PostProcesSingleStream(info.rawStream, Info(), sizeof(typename TRAITS::PIXEL))); } if (Info().colorTransformation == ColorTransformation::None) return new ProcessTransformed >(info, Info(), TransformNone()); if (Info().bitsPerSample == sizeof(SAMPLE) * 8) { switch (Info().colorTransformation) { case ColorTransformation::HP1: return new ProcessTransformed>(info, Info(), TransformHp1()); case ColorTransformation::HP2: return new ProcessTransformed>(info, Info(), TransformHp2()); case ColorTransformation::HP3: return new ProcessTransformed>(info, Info(), TransformHp3()); default: std::ostringstream message; message << "Color transformation " << Info().colorTransformation << " is not supported."; throw CreateSystemError(ApiResult::UnsupportedColorTransform, message.str()); } } if (Info().bitsPerSample > 8) { int shift = 16 - Info().bitsPerSample; switch (Info().colorTransformation) { case ColorTransformation::HP1: return new ProcessTransformed>>(info, Info(), TransformShifted>(shift)); case ColorTransformation::HP2: return new ProcessTransformed>>(info, Info(), TransformShifted>(shift)); case ColorTransformation::HP3: return new ProcessTransformed>>(info, Info(), TransformShifted>(shift)); default: std::ostringstream message; message << "Color transformation " << Info().colorTransformation << " is not supported."; throw CreateSystemError(ApiResult::UnsupportedColorTransform, message.str()); } } throw std::system_error(static_cast(ApiResult::UnsupportedBitDepthForTransform), CharLSCategoryInstance()); } // Setup codec for encoding and calls DoScan template size_t JlsCodec::EncodeScan(std::unique_ptr processLine, ByteStreamInfo& compressedData, void* pvoidCompare) { STRATEGY::_processLine = std::move(processLine); ByteStreamInfo info = { nullptr, static_cast(pvoidCompare), compressedData.count }; if (pvoidCompare) { STRATEGY::_qdecoder = std::unique_ptr(new JlsCodec(traits, Info())); STRATEGY::_qdecoder->Init(info); } STRATEGY::Init(compressedData); DoScan(); return STRATEGY::GetLength(); } // Setup codec for decoding and calls DoScan template void JlsCodec::DecodeScan(std::unique_ptr processLine, const JlsRect& rect, ByteStreamInfo& compressedData, bool bCompare) { STRATEGY::_processLine = std::move(processLine); uint8_t* compressedBytes = const_cast(static_cast(compressedData.rawData)); _bCompare = bCompare; _rect = rect; STRATEGY::Init(compressedData); DoScan(); SkipBytes(compressedData, STRATEGY::GetCurBytePos() - compressedBytes); } // Initialize the codec data structures. Depends on JPEG-LS parameters like T1-T3. template void JlsCodec::InitParams(int32_t t1, int32_t t2, int32_t t3, int32_t nReset) { T1 = t1; T2 = t2; T3 = t3; InitQuantizationLUT(); int32_t A = MAX(2, (traits.RANGE + 32)/64); for (unsigned int Q = 0; Q < sizeof(_contexts) / sizeof(_contexts[0]); ++Q) { _contexts[Q] = JlsContext(A); } _contextRunmode[0] = CContextRunMode(MAX(2, (traits.RANGE + 32)/64), 0, nReset); _contextRunmode[1] = CContextRunMode(MAX(2, (traits.RANGE + 32)/64), 1, nReset); _RUNindex = 0; } #endif