@@ -53,10 +53,12 @@ LJpegDecompressor::LJpegDecompressor(RawImage img, iRectangle2D imgFrame_,
5353 Frame frame_,
5454 std::vector<PerComponentRecipe> rec_,
5555 int numRowsPerRestartInterval_,
56+ int predictorMode_,
5657 Array1DRef<const uint8_t > input_)
5758 : mRaw (std::move(img)), input(input_), imgFrame(imgFrame_),
5859 frame (std::move(frame_)), rec(std::move(rec_)),
59- numRowsPerRestartInterval(numRowsPerRestartInterval_) {
60+ numRowsPerRestartInterval(numRowsPerRestartInterval_),
61+ predictorMode(predictorMode_) {
6062
6163 if (mRaw ->getDataType () != RawImageType::UINT16)
6264 ThrowRDE (" Unexpected data type (%u)" ,
@@ -100,7 +102,7 @@ LJpegDecompressor::LJpegDecompressor(RawImage img, iRectangle2D imgFrame_,
100102 ThrowRDE (" Unsupported number of components: %u" , frame.cps );
101103
102104 if (rec.size () != static_cast <unsigned >(frame.cps ))
103- ThrowRDE (" Must have exactly one recepie per component" );
105+ ThrowRDE (" Must have exactly one recipe per component" );
104106
105107 for (const auto & recip : rec) {
106108 if (!recip.ht .isFullDecode ())
@@ -136,7 +138,7 @@ LJpegDecompressor::LJpegDecompressor(RawImage img, iRectangle2D imgFrame_,
136138 }
137139
138140 if (numRowsPerRestartInterval < 1 )
139- ThrowRDE (" Number of rows per restart interval must be positives " );
141+ ThrowRDE (" Number of rows per restart interval must be positive " );
140142
141143 // How many full pixel blocks will we produce?
142144 fullBlocks = tileRequiredWidth / frame.cps ; // Truncating division!
@@ -169,7 +171,8 @@ std::array<uint16_t, N_COMP> LJpegDecompressor::getInitialPreds() const {
169171
170172template <int N_COMP, bool WeirdWidth>
171173void LJpegDecompressor::decodeRowN (
172- CroppedArray1DRef<uint16_t > outRow, std::array<uint16_t , N_COMP> pred,
174+ CroppedArray1DRef<uint16_t > outRow, CroppedArray1DRef<uint16_t > prevRow,
175+ std::array<uint16_t , N_COMP> pred, int predMode,
173176 std::array<std::reference_wrapper<const PrefixCodeDecoder<>>, N_COMP> ht,
174177 BitStreamerJPEG& bs) const {
175178 // FIXME: predictor may have value outside of the uint16_t.
@@ -179,10 +182,39 @@ void LJpegDecompressor::decodeRowN(
179182 // For x, we first process all full pixel blocks within the image buffer ...
180183 for (; col < N_COMP * fullBlocks; col += N_COMP) {
181184 for (int i = 0 ; i != N_COMP; ++i) {
182- pred[i] =
185+ outRow (col + i) =
183186 uint16_t (pred[i] + (static_cast <const PrefixCodeDecoder<>&>(ht[i]))
184187 .decodeDifference (bs));
185- outRow (col + i) = pred[i];
188+ if (col < N_COMP * (fullBlocks - 1 )) {
189+ int32_t predA = outRow (col + i);
190+ int32_t predB = predMode > 1 ? prevRow (col + N_COMP + i) : 0 ;
191+ int32_t predC = predMode > 1 ? prevRow (col + i) : 0 ;
192+ switch (predMode) {
193+ case 1 :
194+ pred[i] = predA;
195+ break ;
196+ case 2 :
197+ pred[i] = predB;
198+ break ;
199+ case 3 :
200+ pred[i] = predC;
201+ break ;
202+ case 4 :
203+ pred[i] = predA + predB - predC;
204+ break ;
205+ case 5 :
206+ pred[i] = predA + ((predB - predC) >> 1 );
207+ break ;
208+ case 6 :
209+ pred[i] = predB + ((predA - predC) >> 1 );
210+ break ;
211+ case 7 :
212+ pred[i] = (predA + predB) >> 1 ;
213+ break ;
214+ default :
215+ __builtin_unreachable ();
216+ }
217+ }
186218 }
187219 }
188220
@@ -197,10 +229,38 @@ void LJpegDecompressor::decodeRowN(
197229 invariant (trailingPixels < N_COMP);
198230 int c = 0 ;
199231 for (; c < trailingPixels; ++c) {
200- pred[c] =
232+ // Continue predictor update skipped at last full block
233+ int32_t predA = outRow (col - N_COMP + c);
234+ int32_t predB = predMode > 1 ? prevRow (col + c) : 0 ;
235+ int32_t predC = predMode > 1 ? prevRow (col - N_COMP + c) : 0 ;
236+ switch (predMode) {
237+ case 1 :
238+ pred[c] = predA;
239+ break ;
240+ case 2 :
241+ pred[c] = predB;
242+ break ;
243+ case 3 :
244+ pred[c] = predC;
245+ break ;
246+ case 4 :
247+ pred[c] = predA + predB - predC;
248+ break ;
249+ case 5 :
250+ pred[c] = predA + ((predB - predC) >> 1 );
251+ break ;
252+ case 6 :
253+ pred[c] = predB + ((predA - predC) >> 1 );
254+ break ;
255+ case 7 :
256+ pred[c] = (predA + predB) >> 1 ;
257+ break ;
258+ default :
259+ __builtin_unreachable ();
260+ }
261+ outRow (col + c) =
201262 uint16_t (pred[c] + (static_cast <const PrefixCodeDecoder<>&>(ht[c]))
202263 .decodeDifference (bs));
203- outRow (col + c) = pred[c];
204264 }
205265 // Discard the rest of the block.
206266 invariant (c < N_COMP);
@@ -251,8 +311,9 @@ ByteStream::size_type LJpegDecompressor::decodeN() const {
251311 ByteStream inputStream (DataBuffer (input, Endianness::little));
252312 for (int restartIntervalIndex = 0 ;
253313 restartIntervalIndex != numRestartIntervals; ++restartIntervalIndex) {
254- auto pred = getInitialPreds<N_COMP>();
255- auto predNext = Array1DRef (pred.data (), pred.size ());
314+ auto predInit = getInitialPreds<N_COMP>();
315+ auto predNext = Array1DRef (predInit.data (), predInit.size ());
316+ std::array<uint16_t , N_COMP> pred;
256317
257318 if (restartIntervalIndex != 0 ) {
258319 auto marker = peekMarker (inputStream);
@@ -283,14 +344,17 @@ ByteStream::size_type LJpegDecompressor::decodeN() const {
283344 }
284345
285346 auto outRow = img[row];
347+ auto prevRow = row > 0 ? img[row - 1 ] : img[row];
286348 copy_n (predNext.begin (), N_COMP, pred.data ());
287349 // the predictor for the next line is the start of this line
288350 predNext = outRow
289351 .getBlock (/* size=*/ N_COMP,
290352 /* index=*/ 0 )
291353 .getAsArray1DRef ();
354+ // the predictor mode is always horizontal on the first line
355+ int predMode = row == 0 ? 1 : predictorMode;
292356
293- decodeRowN<N_COMP, WeirdWidth>(outRow, pred, ht, bs);
357+ decodeRowN<N_COMP, WeirdWidth>(outRow, prevRow, pred, predMode , ht, bs);
294358 }
295359
296360 inputStream.skipBytes (bs.getStreamPosition ());
0 commit comments