diff --git a/src/librawspeed/decompressors/LJpegDecoder.cpp b/src/librawspeed/decompressors/LJpegDecoder.cpp index 8bf8b222d..7b2f22a79 100644 --- a/src/librawspeed/decompressors/LJpegDecoder.cpp +++ b/src/librawspeed/decompressors/LJpegDecoder.cpp @@ -92,7 +92,7 @@ void LJpegDecoder::decode(uint32_t offsetX, uint32_t offsetY, uint32_t width, void LJpegDecoder::decodeScan() { invariant(frame.cps > 0); - if (predictorMode != 1) + if ((predictorMode < 1) || (predictorMode > 7)) ThrowRDE("Unsupported predictor mode: %u", predictorMode); for (uint32_t i = 0; i < frame.cps; i++) @@ -113,7 +113,8 @@ void LJpegDecoder::decodeScan() { LJpegDecompressor d( mRaw, iRectangle2D({(int)offX, (int)offY}, {(int)w, (int)h}), - LJpegDecompressor::Frame{N_COMP, iPoint2D(frame.w, frame.h)}, rec, input); + LJpegDecompressor::Frame{N_COMP, iPoint2D(frame.w, frame.h)}, rec, + predictorMode, input); d.decode(); } diff --git a/src/librawspeed/decompressors/LJpegDecompressor.cpp b/src/librawspeed/decompressors/LJpegDecompressor.cpp index 090898f63..7efc8c1c6 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.cpp +++ b/src/librawspeed/decompressors/LJpegDecompressor.cpp @@ -40,9 +40,9 @@ namespace rawspeed { LJpegDecompressor::LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame_, Frame frame_, std::vector rec_, - ByteStream bs) + int predictorMode_, ByteStream bs) : mRaw(img), input(bs), imgFrame(imgFrame_), frame(std::move(frame_)), - rec(std::move(rec_)) { + rec(std::move(rec_)), predictorMode(predictorMode_) { if (mRaw->getDataType() != RawImageType::UINT16) ThrowRDE("Unexpected data type (%u)", static_cast(mRaw->getDataType())); @@ -157,8 +157,9 @@ template void LJpegDecompressor::decodeN() { mRaw->getCpp() * imgFrame.dim.x, imgFrame.dim.y); const auto ht = getPrefixCodeDecoders(); - auto pred = getInitialPreds(); - uint16_t* predNext = pred.data(); + auto predInit = getInitialPreds(); + uint16_t* predNext = predInit.data(); + std::array pred; BitPumpJPEG bitStream(input); @@ -177,9 +178,13 @@ template void LJpegDecompressor::decodeN() { for (int row = 0; row < imgFrame.dim.y; ++row) { int col = 0; - copy_n(predNext, N_COMP, pred.data()); + for (int i = 0; i != N_COMP; ++i) { + pred[i] = predNext[i]; + } // the predictor for the next line is the start of this line predNext = &img(row, col); + // the predictor mode is always horizontal on the first line + int predMode = row == 0 ? 1 : predictorMode; // FIXME: predictor may have value outside of the uint16_t. // https://github.com/darktable-org/rawspeed/issues/175 @@ -187,10 +192,39 @@ template void LJpegDecompressor::decodeN() { // For x, we first process all full pixel blocks within the image buffer ... for (; col < N_COMP * fullBlocks; col += N_COMP) { for (int i = 0; i != N_COMP; ++i) { - pred[i] = uint16_t( + img(row, col + i) = uint16_t( pred[i] + ((const PrefixCodeDecoder<>&)(ht[i])).decodeDifference(bitStream)); - img(row, col + i) = pred[i]; + if (col < N_COMP * (fullBlocks - 1)) { + int32_t predA = img(row, col + i); + int32_t predB = predMode > 1 ? img(row - 1, col + N_COMP + i) : 0; + int32_t predC = predMode > 1 ? img(row - 1, col + i) : 0; + switch (predMode) { + case 1: + pred[i] = predA; + break; + case 2: + pred[i] = predB; + break; + case 3: + pred[i] = predC; + break; + case 4: + pred[i] = predA + predB - predC; + break; + case 5: + pred[i] = predA + ((predB - predC) >> 1); + break; + case 6: + pred[i] = predB + ((predA - predC) >> 1); + break; + case 7: + pred[i] = (predA + predB) >> 1; + break; + default: + __builtin_unreachable(); + } + } } } @@ -205,10 +239,38 @@ template void LJpegDecompressor::decodeN() { invariant(trailingPixels < N_COMP); int c = 0; for (; c < trailingPixels; ++c) { - pred[c] = uint16_t( + // Continue predictor update skipped at last full block + int32_t predA = img(row, col - N_COMP + c); + int32_t predB = predMode > 1 ? img(row - 1, col + c) : 0; + int32_t predC = predMode > 1 ? img(row - 1, col - N_COMP + c) : 0; + switch (predMode) { + case 1: + pred[c] = predA; + break; + case 2: + pred[c] = predB; + break; + case 3: + pred[c] = predC; + break; + case 4: + pred[c] = predA + predB - predC; + break; + case 5: + pred[c] = predA + ((predB - predC) >> 1); + break; + case 6: + pred[c] = predB + ((predA - predC) >> 1); + break; + case 7: + pred[c] = (predA + predB) >> 1; + break; + default: + __builtin_unreachable(); + } + img(row, col + c) = uint16_t( pred[c] + ((const PrefixCodeDecoder<>&)(ht[c])).decodeDifference(bitStream)); - img(row, col + c) = pred[c]; } // Discard the rest of the block. invariant(c < N_COMP); diff --git a/src/librawspeed/decompressors/LJpegDecompressor.h b/src/librawspeed/decompressors/LJpegDecompressor.h index 44151a2d6..a72f700b8 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.h +++ b/src/librawspeed/decompressors/LJpegDecompressor.h @@ -56,6 +56,7 @@ class LJpegDecompressor final { const Frame frame; const std::vector rec; + int predictorMode; int fullBlocks = 0; int trailingPixels = 0; @@ -76,7 +77,8 @@ class LJpegDecompressor final { public: LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame, Frame frame, - std::vector rec, ByteStream bs); + std::vector rec, int predictorMode, + ByteStream bs); void decode(); };