00001 // 00002 // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. 00003 // 00004 00005 #ifndef CHARLS_SCAN 00006 #define CHARLS_SCAN 00007 00008 #include "dcmtk/ofstd/ofmap.h" /* For OFPair */ 00009 #include "dcmtk/ofstd/oftypes.h" /* For OFTypename */ 00010 00011 #include "lokuptbl.h" 00012 00013 // This file contains the code for handling a "scan". Usually an image is encoded as a single scan. 00014 00015 00016 #ifdef _MSC_VER 00017 #pragma warning (disable: 4127) 00018 #endif 00019 00020 00021 extern CTable decodingTables[16]; 00022 extern OFVector<signed char> rgquant8Ll; 00023 extern OFVector<signed char> rgquant10Ll; 00024 extern OFVector<signed char> rgquant12Ll; 00025 extern OFVector<signed char> rgquant16Ll; 00026 // 00027 // Apply 00028 // 00029 inlinehint LONG ApplySign(LONG i, LONG sign) 00030 { return (sign ^ i) - sign; } 00031 00032 00033 LONG CLAMP(LONG i, LONG j, LONG MAXVAL) 00034 { 00035 if (i > MAXVAL || i < j) 00036 return j; 00037 00038 return i; 00039 } 00040 00041 Presets ComputeDefault(LONG MAXVAL, LONG NEAR) 00042 { 00043 Presets preset; 00044 00045 LONG FACTOR = (MIN(MAXVAL, 4095) + 128)/256; 00046 00047 preset.T1 = CLAMP(FACTOR * (BASIC_T1 - 2) + 2 + 3*NEAR, NEAR + 1, MAXVAL); 00048 preset.T2 = CLAMP(FACTOR * (BASIC_T2 - 3) + 3 + 5*NEAR, preset.T1, MAXVAL); 00049 preset.T3 = CLAMP(FACTOR * (BASIC_T3 - 4) + 4 + 7*NEAR, preset.T2, MAXVAL); 00050 preset.MAXVAL = MAXVAL; 00051 preset.RESET = BASIC_RESET; 00052 return preset; 00053 } 00054 00055 00056 // Two alternatives for GetPredictedValue() (second is slightly faster due to reduced branching) 00057 00058 #if 0 00059 00060 inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc) 00061 { 00062 if (Ra < Rb) 00063 { 00064 if (Rc < Ra) 00065 return Rb; 00066 00067 if (Rc > Rb) 00068 return Ra; 00069 } 00070 else 00071 { 00072 if (Rc < Rb) 00073 return Ra; 00074 00075 if (Rc > Ra) 00076 return Rb; 00077 } 00078 00079 return Ra + Rb - Rc; 00080 } 00081 00082 #else 00083 00084 inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc) 00085 { 00086 // sign trick reduces the number of if statements (branches) 00087 LONG sgn = BitWiseSign(Rb - Ra); 00088 00089 // is Ra between Rc and Rb? 00090 if ((sgn ^ (Rc - Ra)) < 0) 00091 { 00092 return Rb; 00093 } 00094 else if ((sgn ^ (Rb - Rc)) < 0) 00095 { 00096 return Ra; 00097 } 00098 00099 // default case, valid if Rc element of [Ra,Rb] 00100 return Ra + Rb - Rc; 00101 } 00102 00103 #endif 00104 00105 inlinehint LONG UnMapErrVal(LONG mappedError) 00106 { 00107 //LONG sign = ~((mappedError & 1) - 1); 00108 LONG sign = LONG(mappedError << (LONG_BITCOUNT-1)) >> (LONG_BITCOUNT-1); 00109 return sign ^ (mappedError >> 1); 00110 } 00111 00112 00113 00114 inlinehint LONG GetMappedErrVal(LONG Errval) 00115 { 00116 LONG mappedError = (Errval >> (LONG_BITCOUNT-2)) ^ (2 * Errval); 00117 return mappedError; 00118 } 00119 00120 00121 00122 inlinehint LONG ComputeContextID(LONG Q1, LONG Q2, LONG Q3) 00123 { return (Q1*9 + Q2)*9 + Q3; } 00124 00125 00126 // 00127 // 00128 // 00129 template <class TRAITS, class STRATEGY> 00130 class JlsCodec : public STRATEGY 00131 { 00132 public: 00133 typedef typename TRAITS::PIXEL PIXEL; 00134 typedef typename TRAITS::SAMPLE SAMPLE; 00135 00136 public: 00137 00138 JlsCodec(const TRAITS& inTraits, const JlsParameters& info) : STRATEGY(info), 00139 traits(inTraits), 00140 _rect(), 00141 _width(0), 00142 T1(0), 00143 T2(0), 00144 T3(0), 00145 _RUNindex(0), 00146 _pquant(0), 00147 _bCompare(0) 00148 00149 { 00150 if (Info().ilv == ILV_NONE) 00151 { 00152 Info().components = 1; 00153 } 00154 } 00155 00156 00157 void SetPresets(const JlsCustomParameters& presets) 00158 { 00159 00160 Presets presetDefault = ComputeDefault(traits.MAXVAL, traits.NEAR); 00161 00162 InitParams(presets.T1 != 0 ? presets.T1 : presetDefault.T1, 00163 presets.T2 != 0 ? presets.T2 : presetDefault.T2, 00164 presets.T3 != 0 ? presets.T3 : presetDefault.T3, 00165 presets.RESET != 0 ? presets.RESET : presetDefault.RESET); 00166 } 00167 00168 00169 bool IsInterleaved() 00170 { 00171 if (Info().ilv == ILV_NONE) 00172 return false; 00173 00174 if (Info().components == 1) 00175 return false; 00176 00177 return true; 00178 } 00179 00180 JlsParameters& Info() { return STRATEGY::_info; } 00181 00182 signed char QuantizeGratientOrg(LONG Di); 00183 inlinehint LONG QuantizeGratient(LONG Di) 00184 { 00185 ASSERT(QuantizeGratientOrg(Di) == *(_pquant + Di)); 00186 return *(_pquant + Di); 00187 } 00188 00189 void InitQuantizationLUT(); 00190 00191 LONG DecodeValue(LONG k, LONG limit, LONG qbpp); 00192 inlinehint void EncodeMappedValue(LONG k, LONG mappedError, LONG limit); 00193 00194 void IncrementRunIndex() 00195 { _RUNindex = MIN(31,_RUNindex + 1); } 00196 void DecrementRunIndex() 00197 { _RUNindex = MAX(0,_RUNindex - 1); } 00198 00199 LONG DecodeRIError(CContextRunMode& ctx); 00200 Triplet<SAMPLE> DecodeRIPixel(Triplet<SAMPLE> Ra, Triplet<SAMPLE> Rb); 00201 SAMPLE DecodeRIPixel(LONG Ra, LONG Rb) 00202 { 00203 if (ABS(Ra - Rb) <= traits.NEAR) 00204 { 00205 LONG ErrVal = DecodeRIError(_contextRunmode[1]); 00206 return static_cast<SAMPLE>(traits.ComputeReconstructedSample(Ra, ErrVal)); 00207 } 00208 else 00209 { 00210 LONG ErrVal = DecodeRIError(_contextRunmode[0]); 00211 return static_cast<SAMPLE>(traits.ComputeReconstructedSample(Rb, ErrVal * Sign(Rb - Ra))); 00212 } 00213 } 00214 00215 00216 LONG DecodeRunPixels(PIXEL Ra, PIXEL* ptype, LONG cpixelMac); 00217 LONG DoRunMode(LONG index, DecoderStrategy*); 00218 00219 void EncodeRIError(CContextRunMode& ctx, LONG Errval); 00220 SAMPLE EncodeRIPixel(LONG x, LONG Ra, LONG Rb) 00221 { 00222 if (ABS(Ra - Rb) <= traits.NEAR) 00223 { 00224 LONG ErrVal = traits.ComputeErrVal(x - Ra); 00225 EncodeRIError(_contextRunmode[1], ErrVal); 00226 return static_cast<SAMPLE>(traits.ComputeReconstructedSample(Ra, ErrVal)); 00227 } 00228 else 00229 { 00230 LONG ErrVal = traits.ComputeErrVal((x - Rb) * Sign(Rb - Ra)); 00231 EncodeRIError(_contextRunmode[0], ErrVal); 00232 return static_cast<SAMPLE>(traits.ComputeReconstructedSample(Rb, ErrVal * Sign(Rb - Ra))); 00233 } 00234 } 00235 00236 00237 Triplet<SAMPLE> EncodeRIPixel(Triplet<SAMPLE> x, Triplet<SAMPLE> Ra, Triplet<SAMPLE> Rb); 00238 void EncodeRunPixels(LONG runLength, bool bEndofline); 00239 LONG DoRunMode(LONG index, EncoderStrategy*); 00240 00241 // Encode/decode a single sample. Performancewise the #1 important functions 00242 SAMPLE DoRegular(LONG Qs, LONG, LONG pred, DecoderStrategy*) 00243 { 00244 LONG sign = BitWiseSign(Qs); 00245 JlsContext& ctx = _contexts[ApplySign(Qs, sign)]; 00246 LONG k = ctx.GetGolomb(); 00247 LONG Px = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign)); 00248 00249 LONG ErrVal; 00250 const Code& code = decodingTables[k].Get(STRATEGY::PeekByte()); 00251 if (code.GetLength() != 0) 00252 { 00253 STRATEGY::Skip(code.GetLength()); 00254 ErrVal = code.GetValue(); 00255 ASSERT(ABS(ErrVal) < 65535); 00256 } 00257 else 00258 { 00259 ErrVal = UnMapErrVal(DecodeValue(k, traits.LIMIT, traits.qbpp)); 00260 if (ABS(ErrVal) > 65535) 00261 throw JlsException(InvalidCompressedData); 00262 } 00263 ErrVal = ErrVal ^ ((traits.NEAR == 0) ? ctx.GetErrorCorrection(k) : 0); 00264 ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); 00265 ErrVal = ApplySign(ErrVal, sign); 00266 return traits.ComputeReconstructedSample(Px, ErrVal); 00267 } 00268 00269 SAMPLE DoRegular(LONG Qs, LONG x, LONG pred, EncoderStrategy*) 00270 { 00271 LONG sign = BitWiseSign(Qs); 00272 JlsContext& ctx = _contexts[ApplySign(Qs, sign)]; 00273 LONG k = ctx.GetGolomb(); 00274 LONG Px = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign)); 00275 00276 LONG ErrVal = traits.ComputeErrVal(ApplySign(x - Px, sign)); 00277 00278 EncodeMappedValue(k, GetMappedErrVal(ctx.GetErrorCorrection(k | traits.NEAR) ^ ErrVal), traits.LIMIT); 00279 ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); 00280 ASSERT(traits.IsNear(traits.ComputeReconstructedSample(Px, ApplySign(ErrVal, sign)), x)); 00281 return static_cast<SAMPLE>(traits.ComputeReconstructedSample(Px, ApplySign(ErrVal, sign))); 00282 } 00283 00284 void DoLine(SAMPLE* pdummy); 00285 void DoLine(Triplet<SAMPLE>* pdummy); 00286 void DoScan(BYTE* compressedBytes, size_t compressedLength); 00287 00288 public: 00289 ProcessLine* CreateProcess(void* pvoidOut); 00290 void InitDefault(); 00291 void InitParams(LONG t1, LONG t2, LONG t3, LONG nReset); 00292 00293 size_t EncodeScan(const void* rawData, void* pvoidOut, size_t compressedLength, void* pvoidCompare); 00294 size_t DecodeScan(void* rawData, const JlsRect& size, const void* compressedData, size_t compressedLength, bool bCompare); 00295 00296 protected: 00297 // codec parameters 00298 TRAITS traits; 00299 JlsRect _rect; 00300 int _width; 00301 LONG T1; 00302 LONG T2; 00303 LONG T3; 00304 00305 // compression context 00306 JlsContext _contexts[365]; 00307 CContextRunMode _contextRunmode[2]; 00308 LONG _RUNindex; 00309 PIXEL* _previousLine; // previous line ptr 00310 PIXEL* _currentLine; // current line ptr 00311 00312 00313 // quantization lookup table 00314 signed char* _pquant; 00315 OFVector<signed char> _rgquant; 00316 00317 // debugging 00318 bool _bCompare; 00319 }; 00320 00321 00322 // Functions to build tables used to decode short golomb codes. 00323 00324 inlinehint OFPair<LONG, LONG> CreateEncodedValue(LONG k, LONG mappedError) 00325 { 00326 LONG highbits = mappedError >> k; 00327 return OFMake_pair<LONG, LONG>(highbits + k + 1, (LONG(1) << k) | (mappedError & ((LONG(1) << k) - 1))); 00328 } 00329 00330 00331 CTable InitTable(LONG k) 00332 { 00333 CTable table; 00334 short nerr; 00335 for (nerr = 0; ; nerr++) 00336 { 00337 // Q is not used when k != 0 00338 LONG merrval = GetMappedErrVal(nerr);//, k, -1); 00339 OFPair<LONG, LONG> paircode = CreateEncodedValue(k, merrval); 00340 if (paircode.first > CTable::cbit) 00341 break; 00342 00343 Code code = Code( nerr, short(paircode.first) ); 00344 table.AddEntry(BYTE(paircode.second), code); 00345 } 00346 00347 for (nerr = -1; ; nerr--) 00348 { 00349 // Q is not used when k != 0 00350 LONG merrval = GetMappedErrVal(nerr);//, k, -1); 00351 OFPair<LONG, LONG> paircode = CreateEncodedValue(k, merrval); 00352 if (paircode.first > CTable::cbit) 00353 break; 00354 00355 Code code = Code(nerr, short(paircode.first)); 00356 table.AddEntry(BYTE(paircode.second), code); 00357 } 00358 00359 return table; 00360 } 00361 00362 00363 // Encoding/decoding of golomb codes 00364 00365 template<class TRAITS, class STRATEGY> 00366 LONG JlsCodec<TRAITS,STRATEGY>::DecodeValue(LONG k, LONG limit, LONG qbpp) 00367 { 00368 LONG highbits = STRATEGY::ReadHighbits(); 00369 00370 if (highbits >= limit - (qbpp + 1)) 00371 return STRATEGY::ReadValue(qbpp) + 1; 00372 00373 if (k == 0) 00374 return highbits; 00375 00376 return (highbits << k) + STRATEGY::ReadValue(k); 00377 } 00378 00379 00380 00381 template<class TRAITS, class STRATEGY> 00382 inlinehint void JlsCodec<TRAITS,STRATEGY>::EncodeMappedValue(LONG k, LONG mappedError, LONG limit) 00383 { 00384 LONG highbits = mappedError >> k; 00385 00386 if (highbits < limit - traits.qbpp - 1) 00387 { 00388 if (highbits + 1 > 31) 00389 { 00390 STRATEGY::AppendToBitStream(0, highbits / 2); 00391 highbits = highbits - highbits / 2; 00392 } 00393 STRATEGY::AppendToBitStream(1, highbits + 1); 00394 STRATEGY::AppendToBitStream((mappedError & ((1 << k) - 1)), k); 00395 return; 00396 } 00397 00398 if (limit - traits.qbpp > 31) 00399 { 00400 STRATEGY::AppendToBitStream(0, 31); 00401 STRATEGY::AppendToBitStream(1, limit - traits.qbpp - 31); 00402 } 00403 else 00404 { 00405 STRATEGY::AppendToBitStream(1, limit - traits.qbpp); 00406 } 00407 STRATEGY::AppendToBitStream((mappedError - 1) & ((1 << traits.qbpp) - 1), traits.qbpp); 00408 } 00409 00410 00411 // Sets up a lookup table to "Quantize" sample difference. 00412 00413 template<class TRAITS, class STRATEGY> 00414 void JlsCodec<TRAITS,STRATEGY>::InitQuantizationLUT() 00415 { 00416 // for lossless mode with default parameters, we have precomputed te luts for bitcounts 8,10,12 and 16 00417 if (traits.NEAR == 0 && traits.MAXVAL == (1 << traits.bpp) - 1) 00418 { 00419 Presets presets = ComputeDefault(traits.MAXVAL, traits.NEAR); 00420 if (presets.T1 == T1 && presets.T2 == T2 && presets.T3 == T3) 00421 { 00422 if (traits.bpp == 8) 00423 { 00424 _pquant = &rgquant8Ll[rgquant8Ll.size() / 2 ]; 00425 return; 00426 } 00427 if (traits.bpp == 10) 00428 { 00429 _pquant = &rgquant10Ll[rgquant10Ll.size() / 2 ]; 00430 return; 00431 } 00432 if (traits.bpp == 12) 00433 { 00434 _pquant = &rgquant12Ll[rgquant12Ll.size() / 2 ]; 00435 return; 00436 } 00437 if (traits.bpp == 16) 00438 { 00439 _pquant = &rgquant16Ll[rgquant16Ll.size() / 2 ]; 00440 return; 00441 } 00442 } 00443 } 00444 00445 LONG RANGE = 1 << traits.bpp; 00446 00447 _rgquant.resize(RANGE * 2); 00448 00449 _pquant = &_rgquant[RANGE]; 00450 for (LONG i = -RANGE; i < RANGE; ++i) 00451 { 00452 _pquant[i] = QuantizeGratientOrg(i); 00453 } 00454 } 00455 00456 00457 template<class TRAITS, class STRATEGY> 00458 signed char JlsCodec<TRAITS,STRATEGY>::QuantizeGratientOrg(LONG Di) 00459 { 00460 if (Di <= -T3) return -4; 00461 if (Di <= -T2) return -3; 00462 if (Di <= -T1) return -2; 00463 if (Di < -traits.NEAR) return -1; 00464 if (Di <= traits.NEAR) return 0; 00465 if (Di < T1) return 1; 00466 if (Di < T2) return 2; 00467 if (Di < T3) return 3; 00468 00469 return 4; 00470 } 00471 00472 00473 00474 // RI = Run interruption: functions that handle the sample terminating a run. 00475 00476 template<class TRAITS, class STRATEGY> 00477 LONG JlsCodec<TRAITS,STRATEGY>::DecodeRIError(CContextRunMode& ctx) 00478 { 00479 LONG k = ctx.GetGolomb(); 00480 LONG EMErrval = DecodeValue(k, traits.LIMIT - J[_RUNindex]-1, traits.qbpp); 00481 LONG Errval = ctx.ComputeErrVal(EMErrval + ctx._nRItype, k); 00482 ctx.UpdateVariables(Errval, EMErrval); 00483 return Errval; 00484 } 00485 00486 00487 00488 template<class TRAITS, class STRATEGY> 00489 void JlsCodec<TRAITS,STRATEGY>::EncodeRIError(CContextRunMode& ctx, LONG Errval) 00490 { 00491 LONG k = ctx.GetGolomb(); 00492 bool map = ctx.ComputeMap(Errval, k); 00493 LONG EMErrval = 2 * ABS(Errval) - ctx._nRItype - map; 00494 00495 ASSERT(Errval == ctx.ComputeErrVal(EMErrval + ctx._nRItype, k)); 00496 EncodeMappedValue(k, EMErrval, traits.LIMIT-J[_RUNindex]-1); 00497 ctx.UpdateVariables(Errval, EMErrval); 00498 } 00499 00500 00501 template<class TRAITS, class STRATEGY> 00502 Triplet<OFTypename TRAITS::SAMPLE> JlsCodec<TRAITS,STRATEGY>::DecodeRIPixel(Triplet<SAMPLE> Ra, Triplet<SAMPLE> Rb) 00503 { 00504 LONG Errval1 = DecodeRIError(_contextRunmode[0]); 00505 LONG Errval2 = DecodeRIError(_contextRunmode[0]); 00506 LONG Errval3 = DecodeRIError(_contextRunmode[0]); 00507 00508 return Triplet<SAMPLE>(traits.ComputeReconstructedSample(Rb.v1, Errval1 * Sign(Rb.v1 - Ra.v1)), 00509 traits.ComputeReconstructedSample(Rb.v2, Errval2 * Sign(Rb.v2 - Ra.v2)), 00510 traits.ComputeReconstructedSample(Rb.v3, Errval3 * Sign(Rb.v3 - Ra.v3))); 00511 } 00512 00513 00514 00515 template<class TRAITS, class STRATEGY> 00516 Triplet<OFTypename TRAITS::SAMPLE> JlsCodec<TRAITS,STRATEGY>::EncodeRIPixel(Triplet<SAMPLE> x, Triplet<SAMPLE> Ra, Triplet<SAMPLE> Rb) 00517 { 00518 LONG errval1 = traits.ComputeErrVal(Sign(Rb.v1 - Ra.v1) * (x.v1 - Rb.v1)); 00519 EncodeRIError(_contextRunmode[0], errval1); 00520 00521 LONG errval2 = traits.ComputeErrVal(Sign(Rb.v2 - Ra.v2) * (x.v2 - Rb.v2)); 00522 EncodeRIError(_contextRunmode[0], errval2); 00523 00524 LONG errval3 = traits.ComputeErrVal(Sign(Rb.v3 - Ra.v3) * (x.v3 - Rb.v3)); 00525 EncodeRIError(_contextRunmode[0], errval3); 00526 00527 00528 return Triplet<SAMPLE>(traits.ComputeReconstructedSample(Rb.v1, errval1 * Sign(Rb.v1 - Ra.v1)), 00529 traits.ComputeReconstructedSample(Rb.v2, errval2 * Sign(Rb.v2 - Ra.v2)), 00530 traits.ComputeReconstructedSample(Rb.v3, errval3 * Sign(Rb.v3 - Ra.v3))); 00531 } 00532 00533 00534 00535 // RunMode: Functions that handle run-length encoding 00536 00537 template<class TRAITS, class STRATEGY> 00538 void JlsCodec<TRAITS,STRATEGY>::EncodeRunPixels(LONG runLength, bool endOfLine) 00539 { 00540 while (runLength >= LONG(1 << J[_RUNindex])) 00541 { 00542 STRATEGY::AppendOnesToBitStream(1); 00543 runLength = runLength - LONG(1 << J[_RUNindex]); 00544 IncrementRunIndex(); 00545 } 00546 00547 if (endOfLine) 00548 { 00549 if (runLength != 0) 00550 { 00551 STRATEGY::AppendOnesToBitStream(1); 00552 } 00553 } 00554 else 00555 { 00556 STRATEGY::AppendToBitStream(runLength, J[_RUNindex] + 1); // leading 0 + actual remaining length 00557 } 00558 } 00559 00560 00561 template<class TRAITS, class STRATEGY> 00562 LONG JlsCodec<TRAITS,STRATEGY>::DecodeRunPixels(PIXEL Ra, PIXEL* startPos, LONG cpixelMac) 00563 { 00564 LONG index = 0; 00565 while (STRATEGY::ReadBit()) 00566 { 00567 int count = MIN(1 << J[_RUNindex], int(cpixelMac - index)); 00568 index += count; 00569 ASSERT(index <= cpixelMac); 00570 00571 if (count == (1 << J[_RUNindex])) 00572 { 00573 IncrementRunIndex(); 00574 } 00575 00576 if (index == cpixelMac) 00577 break; 00578 } 00579 00580 00581 if (index != cpixelMac) 00582 { 00583 // incomplete run 00584 index += (J[_RUNindex] > 0) ? STRATEGY::ReadValue(J[_RUNindex]) : 0; 00585 } 00586 00587 if (index > cpixelMac) 00588 throw JlsException(InvalidCompressedData); 00589 00590 for (LONG i = 0; i < index; ++i) 00591 { 00592 startPos[i] = Ra; 00593 } 00594 00595 return index; 00596 } 00597 00598 template<class TRAITS, class STRATEGY> 00599 LONG JlsCodec<TRAITS,STRATEGY>::DoRunMode(LONG index, EncoderStrategy*) 00600 { 00601 LONG ctypeRem = _width - index; 00602 PIXEL* ptypeCurX = _currentLine + index; 00603 PIXEL* ptypePrevX = _previousLine + index; 00604 00605 PIXEL Ra = ptypeCurX[-1]; 00606 00607 LONG runLength = 0; 00608 00609 while (traits.IsNear(ptypeCurX[runLength],Ra)) 00610 { 00611 ptypeCurX[runLength] = Ra; 00612 runLength++; 00613 00614 if (runLength == ctypeRem) 00615 break; 00616 } 00617 00618 EncodeRunPixels(runLength, runLength == ctypeRem); 00619 00620 if (runLength == ctypeRem) 00621 return runLength; 00622 00623 ptypeCurX[runLength] = EncodeRIPixel(ptypeCurX[runLength], Ra, ptypePrevX[runLength]); 00624 DecrementRunIndex(); 00625 return runLength + 1; 00626 } 00627 00628 00629 template<class TRAITS, class STRATEGY> 00630 LONG JlsCodec<TRAITS,STRATEGY>::DoRunMode(LONG startIndex, DecoderStrategy*) 00631 { 00632 PIXEL Ra = _currentLine[startIndex-1]; 00633 00634 LONG runLength = DecodeRunPixels(Ra, _currentLine + startIndex, _width - startIndex); 00635 LONG endIndex = startIndex + runLength; 00636 00637 if (endIndex == _width) 00638 return endIndex - startIndex; 00639 00640 // run interruption 00641 PIXEL Rb = _previousLine[endIndex]; 00642 _currentLine[endIndex] = DecodeRIPixel(Ra, Rb); 00643 DecrementRunIndex(); 00644 return endIndex - startIndex + 1; 00645 } 00646 00647 00648 // DoLine: Encodes/Decodes a scanline of samples 00649 00650 template<class TRAITS, class STRATEGY> 00651 void JlsCodec<TRAITS,STRATEGY>::DoLine(SAMPLE*) 00652 { 00653 LONG index = 0; 00654 LONG Rb = _previousLine[index-1]; 00655 LONG Rd = _previousLine[index]; 00656 00657 while(index < _width) 00658 { 00659 LONG Ra = _currentLine[index -1]; 00660 LONG Rc = Rb; 00661 Rb = Rd; 00662 Rd = _previousLine[index + 1]; 00663 00664 LONG Qs = ComputeContextID(QuantizeGratient(Rd - Rb), QuantizeGratient(Rb - Rc), QuantizeGratient(Rc - Ra)); 00665 00666 if (Qs != 0) 00667 { 00668 _currentLine[index] = DoRegular(Qs, _currentLine[index], GetPredictedValue(Ra, Rb, Rc), (STRATEGY*)(NULL)); 00669 index++; 00670 } 00671 else 00672 { 00673 index += DoRunMode(index, (STRATEGY*)(NULL)); 00674 Rb = _previousLine[index-1]; 00675 Rd = _previousLine[index]; 00676 } 00677 } 00678 } 00679 00680 00681 // DoLine: Encodes/Decodes a scanline of triplets in ILV_SAMPLE mode 00682 00683 template<class TRAITS, class STRATEGY> 00684 void JlsCodec<TRAITS,STRATEGY>::DoLine(Triplet<SAMPLE>*) 00685 { 00686 LONG index = 0; 00687 while(index < _width) 00688 { 00689 Triplet<SAMPLE> Ra = _currentLine[index -1]; 00690 Triplet<SAMPLE> Rc = _previousLine[index-1]; 00691 Triplet<SAMPLE> Rb = _previousLine[index]; 00692 Triplet<SAMPLE> Rd = _previousLine[index + 1]; 00693 00694 LONG Qs1 = ComputeContextID(QuantizeGratient(Rd.v1 - Rb.v1), QuantizeGratient(Rb.v1 - Rc.v1), QuantizeGratient(Rc.v1 - Ra.v1)); 00695 LONG Qs2 = ComputeContextID(QuantizeGratient(Rd.v2 - Rb.v2), QuantizeGratient(Rb.v2 - Rc.v2), QuantizeGratient(Rc.v2 - Ra.v2)); 00696 LONG Qs3 = ComputeContextID(QuantizeGratient(Rd.v3 - Rb.v3), QuantizeGratient(Rb.v3 - Rc.v3), QuantizeGratient(Rc.v3 - Ra.v3)); 00697 00698 00699 if (Qs1 == 0 && Qs2 == 0 && Qs3 == 0) 00700 { 00701 index += DoRunMode(index, (STRATEGY*)(NULL)); 00702 } 00703 else 00704 { 00705 Triplet<SAMPLE> Rx; 00706 Rx.v1 = DoRegular(Qs1, _currentLine[index].v1, GetPredictedValue(Ra.v1, Rb.v1, Rc.v1), (STRATEGY*)(NULL)); 00707 Rx.v2 = DoRegular(Qs2, _currentLine[index].v2, GetPredictedValue(Ra.v2, Rb.v2, Rc.v2), (STRATEGY*)(NULL)); 00708 Rx.v3 = DoRegular(Qs3, _currentLine[index].v3, GetPredictedValue(Ra.v3, Rb.v3, Rc.v3), (STRATEGY*)(NULL)); 00709 _currentLine[index] = Rx; 00710 index++; 00711 } 00712 } 00713 } 00714 00715 00716 // DoScan: Encodes or decodes a scan. 00717 // In ILV_SAMPLE mode, multiple components are handled in DoLine 00718 // In ILV_LINE mode, a call do DoLine is made for every component 00719 // In ILV_NONE mode, DoScan is called for each component 00720 00721 template<class TRAITS, class STRATEGY> 00722 void JlsCodec<TRAITS,STRATEGY>::DoScan(BYTE* compressedBytes, size_t compressedLength) 00723 { 00724 _width = Info().width; 00725 00726 STRATEGY::Init(compressedBytes, compressedLength); 00727 00728 LONG pixelstride = _width + 4; 00729 int components = Info().ilv == ILV_LINE ? Info().components : 1; 00730 00731 OFVector<PIXEL> vectmp(2 * components * pixelstride); 00732 OFVector<LONG> rgRUNindex(components); 00733 00734 for (LONG line = 0; line < Info().height; ++line) 00735 { 00736 _previousLine = &vectmp[1]; 00737 _currentLine = &vectmp[1 + components * pixelstride]; 00738 if ((line & 1) == 1) 00739 { 00740 PIXEL *tmp = _previousLine; 00741 _previousLine = _currentLine; 00742 _currentLine = tmp; 00743 } 00744 00745 STRATEGY::OnLineBegin(_width, _currentLine, pixelstride); 00746 00747 for (int component = 0; component < components; ++component) 00748 { 00749 _RUNindex = rgRUNindex[component]; 00750 00751 // initialize edge pixels used for prediction 00752 _previousLine[_width] = _previousLine[_width - 1]; 00753 _currentLine[-1] = _previousLine[0]; 00754 DoLine((PIXEL*) NULL); // dummy arg for overload resolution 00755 00756 rgRUNindex[component] = _RUNindex; 00757 _previousLine += pixelstride; 00758 _currentLine += pixelstride; 00759 } 00760 00761 if (_rect.Y <= line && line < _rect.Y + _rect.Height) 00762 { 00763 STRATEGY::OnLineEnd(_rect.Width, _currentLine + _rect.X - (components * pixelstride), pixelstride); 00764 } 00765 } 00766 00767 STRATEGY::EndScan(); 00768 } 00769 00770 00771 // Factory function for ProcessLine objects to copy/transform unencoded pixels to/from our scanline buffers. 00772 00773 template<class TRAITS, class STRATEGY> 00774 ProcessLine* JlsCodec<TRAITS,STRATEGY>::CreateProcess(void* pvoidOut) 00775 { 00776 if (!IsInterleaved()) 00777 return new PostProcesSingleComponent(pvoidOut, Info(), sizeof(typename TRAITS::PIXEL)); 00778 00779 if (Info().colorTransform == 0) 00780 return new ProcessTransformed<TransformNone<OFTypename TRAITS::SAMPLE> >(pvoidOut, Info(), TransformNone<SAMPLE>()); 00781 00782 if ((Info().bitspersample == sizeof(SAMPLE)*8)) 00783 { 00784 switch(Info().colorTransform) 00785 { 00786 case COLORXFORM_HP1 : return new ProcessTransformed<TransformHp1<SAMPLE> >(pvoidOut, Info(), TransformHp1<SAMPLE>()); break; 00787 case COLORXFORM_HP2 : return new ProcessTransformed<TransformHp2<SAMPLE> >(pvoidOut, Info(), TransformHp2<SAMPLE>()); break; 00788 case COLORXFORM_HP3 : return new ProcessTransformed<TransformHp3<SAMPLE> >(pvoidOut, Info(), TransformHp3<SAMPLE>()); break; 00789 default: throw JlsException(UnsupportedColorTransform); 00790 } 00791 } 00792 else if (Info().bitspersample > 8) 00793 { 00794 int shift = 16 - Info().bitspersample; 00795 switch(Info().colorTransform) 00796 { 00797 case COLORXFORM_HP1 : return new ProcessTransformed<TransformShifted<TransformHp1<USHORT> > >(pvoidOut, Info(), TransformShifted<TransformHp1<USHORT> >(shift)); break; 00798 case COLORXFORM_HP2 : return new ProcessTransformed<TransformShifted<TransformHp2<USHORT> > >(pvoidOut, Info(), TransformShifted<TransformHp2<USHORT> >(shift)); break; 00799 case COLORXFORM_HP3 : return new ProcessTransformed<TransformShifted<TransformHp3<USHORT> > >(pvoidOut, Info(), TransformShifted<TransformHp3<USHORT> >(shift)); break; 00800 default: throw JlsException(UnsupportedColorTransform); 00801 } 00802 } 00803 throw JlsException(UnsupportedBitDepthForTransform); 00804 } 00805 00806 00807 00808 // Setup codec for encoding and calls DoScan 00809 00810 template<class TRAITS, class STRATEGY> 00811 size_t JlsCodec<TRAITS,STRATEGY>::EncodeScan(const void* rawData, void* compressedData, size_t compressedLength, void* pvoidCompare) 00812 { 00813 STRATEGY::_processLine = OFauto_ptr<ProcessLine>(CreateProcess(const_cast<void*>(rawData))); 00814 00815 BYTE* compressedBytes = static_cast<BYTE*>(compressedData); 00816 00817 if (pvoidCompare != NULL) 00818 { 00819 STRATEGY::_qdecoder = OFauto_ptr<DecoderStrategy>(new JlsCodec<TRAITS,DecoderStrategy>(traits, Info())); 00820 STRATEGY::_qdecoder->Init((BYTE*)pvoidCompare, compressedLength); 00821 } 00822 00823 DoScan(compressedBytes, compressedLength); 00824 00825 return STRATEGY::GetLength(); 00826 00827 } 00828 00829 // Setup codec for decoding and calls DoScan 00830 00831 template<class TRAITS, class STRATEGY> 00832 size_t JlsCodec<TRAITS,STRATEGY>::DecodeScan(void* rawData, const JlsRect& rect, const void* compressedData, size_t compressedLength, bool bCompare) 00833 { 00834 STRATEGY::_processLine = OFauto_ptr<ProcessLine>(CreateProcess(rawData)); 00835 00836 BYTE* compressedBytes = const_cast<BYTE*>(static_cast<const BYTE*>(compressedData)); 00837 _bCompare = bCompare; 00838 00839 BYTE rgbyte[20]; 00840 00841 LONG readBytes = 0; 00842 ::memcpy(rgbyte, compressedBytes, 4); 00843 readBytes += 4; 00844 00845 size_t cbyteScanheader = rgbyte[3] - 2; 00846 00847 if (cbyteScanheader > sizeof(rgbyte)) 00848 throw JlsException(InvalidCompressedData); 00849 00850 ::memcpy(rgbyte, compressedBytes, cbyteScanheader); 00851 readBytes += cbyteScanheader; 00852 00853 _rect = rect; 00854 00855 DoScan(compressedBytes + readBytes, compressedLength - readBytes); 00856 00857 return STRATEGY::GetCurBytePos() - compressedBytes; 00858 } 00859 00860 // Initialize the codec data structures. Depends on JPEG-LS parameters like T1-T3. 00861 00862 template<class TRAITS, class STRATEGY> 00863 void JlsCodec<TRAITS,STRATEGY>::InitParams(LONG t1, LONG t2, LONG t3, LONG nReset) 00864 { 00865 T1 = t1; 00866 T2 = t2; 00867 T3 = t3; 00868 00869 InitQuantizationLUT(); 00870 00871 LONG A = MAX(2, (traits.RANGE + 32)/64); 00872 for (unsigned int Q = 0; Q < sizeof(_contexts) / sizeof(_contexts[0]); ++Q) 00873 { 00874 _contexts[Q] = JlsContext(A); 00875 } 00876 00877 _contextRunmode[0] = CContextRunMode(MAX(2, (traits.RANGE + 32)/64), 0, nReset); 00878 _contextRunmode[1] = CContextRunMode(MAX(2, (traits.RANGE + 32)/64), 1, nReset); 00879 _RUNindex = 0; 00880 } 00881 00882 #endif