diff --git a/src/librawspeed/decompressors/LJpegDecompressor.cpp b/src/librawspeed/decompressors/LJpegDecompressor.cpp index ee67989b9..b1e5e54c8 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.cpp +++ b/src/librawspeed/decompressors/LJpegDecompressor.cpp @@ -91,7 +91,7 @@ void LJpegDecompressor::decodeScan() { assert(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++) @@ -194,6 +194,8 @@ template void LJpegDecompressor::decodeN() { copy_n(predNext, N_COMP, pred.data()); // 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 + uint32_t predMode = row == 0 ? 1 : predictorMode; // FIXME: predictor may have value outside of the uint16_t. // https://github.com/darktable-org/rawspeed/issues/175 @@ -201,8 +203,38 @@ 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(pred[i] + ht[i]->decodeDifference(bitStream)); - img(row, col + i) = pred[i]; + img(row, col + i) = + uint16_t(pred[i] + ht[i]->decodeDifference(bitStream)); + if (col < N_COMP * (fullBlocks - 1)) { + int predA = img(row, col + i); + int predB = predMode > 1 ? img(row - 1, col + N_COMP + i) : 0; + int predC = predMode > 1 ? img(row - 1, col + i) : 0; + switch (predMode) { + case 1: + pred[i] = uint16_t(predA); + break; + case 2: + pred[i] = uint16_t(predB); + break; + case 3: + pred[i] = uint16_t(predC); + break; + case 4: + pred[i] = uint16_t(predA + predB - predC); + break; + case 5: + pred[i] = uint16_t(predA + ((predB - predC) >> 1)); + break; + case 6: + pred[i] = uint16_t(predB + ((predA - predC) >> 1)); + break; + case 7: + pred[i] = uint16_t((predA + predB) >> 1); + break; + default: + ThrowRDE("Unsupported predictor mode: %u", predMode); + } + } } } @@ -217,8 +249,37 @@ template void LJpegDecompressor::decodeN() { assert(trailingPixels < N_COMP); unsigned c = 0; for (; c < trailingPixels; ++c) { - pred[c] = uint16_t(pred[c] + ht[c]->decodeDifference(bitStream)); - img(row, col + c) = pred[c]; + // Continue predictor update skipped at last full block + int predA = img(row, col - N_COMP + c); + int predB = predMode > 1 ? img(row - 1, col + c) : 0; + int predC = predMode > 1 ? img(row - 1, col - N_COMP + c) : 0; + switch (predMode) { + case 1: + pred[c] = uint16_t(predA); + break; + case 2: + pred[c] = uint16_t(predB); + break; + case 3: + pred[c] = uint16_t(predC); + break; + case 4: + pred[c] = uint16_t(predA + predB - predC); + break; + case 5: + pred[c] = uint16_t(predA + ((predB - predC) >> 1)); + break; + case 6: + pred[c] = uint16_t(predB + ((predA - predC) >> 1)); + break; + case 7: + pred[c] = uint16_t((predA + predB) >> 1); + break; + default: + ThrowRDE("Unsupported predictor mode: %u", predMode); + } + img(row, col + c) = + uint16_t(pred[c] + ht[c]->decodeDifference(bitStream)); } // Discard the rest of the block. assert(c < N_COMP);