diff --git a/rtdata/mime-types b/rtdata/mime-types index 505b00140..bfd1ccbd9 100644 --- a/rtdata/mime-types +++ b/rtdata/mime-types @@ -6,6 +6,7 @@ image/png; image/tiff; image/x-adobe-dng; image/x-canon-cr2; +image/x-canon-cr3; image/x-canon-crf; image/x-canon-crw; image/x-fuji-raf; diff --git a/rtdata/rawtherapee.desktop.in b/rtdata/rawtherapee.desktop.in index f6bc3afeb..350afc45e 100644 --- a/rtdata/rawtherapee.desktop.in +++ b/rtdata/rawtherapee.desktop.in @@ -14,7 +14,7 @@ Icon=rawtherapee TryExec=rawtherapee Exec=rawtherapee %f Terminal=false -MimeType=image/jpeg;image/png;image/tiff;image/x-adobe-dng;image/x-canon-cr2;image/x-canon-crf;image/x-canon-crw;image/x-fuji-raf;image/x-hasselblad-3fr;image/x-hasselblad-fff;image/x-jpg;image/x-kodak-dcr;image/x-kodak-k25;image/x-kodak-kdc;image/x-leaf-mos;image/x-leica-rwl;image/x-mamiya-mef;image/x-minolta-mrw;image/x-nikon-nef;image/x-nikon-nrw;image/x-olympus-orf;image/x-panasonic-raw;image/x-panasonic-rw2;image/x-pentax-pef;image/x-pentax-raw;image/x-phaseone-iiq;image/x-raw;image/x-rwz;image/x-samsung-srw;image/x-sigma-x3f;image/x-sony-arq;image/x-sony-arw;image/x-sony-sr2;image/x-sony-srf;image/x-tif; +MimeType=image/jpeg;image/png;image/tiff;image/x-adobe-dng;image/x-canon-cr2;image/x-canon-cr3;image/x-canon-crf;image/x-canon-crw;image/x-fuji-raf;image/x-hasselblad-3fr;image/x-hasselblad-fff;image/x-jpg;image/x-kodak-dcr;image/x-kodak-k25;image/x-kodak-kdc;image/x-leaf-mos;image/x-leica-rwl;image/x-mamiya-mef;image/x-minolta-mrw;image/x-nikon-nef;image/x-nikon-nrw;image/x-olympus-orf;image/x-panasonic-raw;image/x-panasonic-rw2;image/x-pentax-pef;image/x-pentax-raw;image/x-phaseone-iiq;image/x-raw;image/x-rwz;image/x-samsung-srw;image/x-sigma-x3f;image/x-sony-arq;image/x-sony-arw;image/x-sony-sr2;image/x-sony-srf;image/x-tif;inode/directory; Categories=Graphics;Photography;2DGraphics;RasterGraphics;GTK; Keywords=raw;photo;photography;develop;pp3;graphics; StartupNotify=true diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index 4dc2019c1..f4d082199 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -1258,12 +1258,12 @@ float* RawImageSource::CA_correct_RT( int indx = (row * width + col) >> 1; #ifdef __SSE2__ for (; col < width - 7 - cb; col += 8, indx += 4) { - vfloat val = LVFU(RawDataTmp[indx]); + const vfloat val = vmaxf(LVFU(RawDataTmp[indx]), ZEROV); STC2VFU(rawData[row][col], val); } #endif for (; col < width - cb; col += 2, indx++) { - rawData[row][col] = RawDataTmp[indx]; + rawData[row][col] = std::max(0.f, RawDataTmp[indx]); } } diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index f58afde5e..6bce68d1a 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -103,6 +103,7 @@ set(RTENGINESOURCEFILES labimage.cc lcp.cc lj92.c + lmmse_demosaic.cc loadinitial.cc myfile.cc panasonic_decoders.cc diff --git a/rtengine/amaze_demosaic_RT.cc b/rtengine/amaze_demosaic_RT.cc index 24c463458..2041f3130 100644 --- a/rtengine/amaze_demosaic_RT.cc +++ b/rtengine/amaze_demosaic_RT.cc @@ -1470,48 +1470,48 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, c vfloat bluev1 = greenv - (temp00v * vdup(LVFU(Dgrb[1][(indx - v1) >> 1])) + (onev - vdup(LVFU(hvwt[(indx + 1 + offset) >> 1]))) * vdup(LVFU(Dgrb[1][(indx + 1 + offset) >> 1])) + (onev - vdup(LVFU(hvwt[(indx - 1 + offset) >> 1]))) * vdup(LVFU(Dgrb[1][(indx - 1 + offset) >> 1])) + temp01v * vdup(LVFU(Dgrb[1][(indx + v1) >> 1]))) * tempv; vfloat redv2 = greenv - vdup(LVFU(Dgrb[0][indx >> 1])); vfloat bluev2 = greenv - vdup(LVFU(Dgrb[1][indx >> 1])); - STVFU(red[row][col], c65535v * vself(selmask, redv1, redv2)); - STVFU(blue[row][col], c65535v * vself(selmask, bluev1, bluev2)); + STVFU(red[row][col], vmaxf(c65535v * vself(selmask, redv1, redv2), ZEROV)); + STVFU(blue[row][col], vmaxf(c65535v * vself(selmask, bluev1, bluev2), ZEROV)); } if(offset == 0) { for (; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++) { float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]); - red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * - temp); - blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * - temp); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * + temp)); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * + temp)); indx++; col++; - red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]); - blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1])); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1])); } if(cc1 & 1) { // width of tile is odd float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]); - red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * - temp); - blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * - temp); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * + temp)); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * + temp)); } } else { for (; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++) { - red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]); - blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1])); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1])); indx++; col++; float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]); - red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * - temp); - blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * - temp); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * + temp)); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * + temp)); } if(cc1 & 1) { // width of tile is odd - red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]); - blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1])); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1])); } } @@ -1520,41 +1520,41 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, c if((fc(cfarray, rr, 2) & 1) == 1) { for (; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++) { float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]); - red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * - temp); - blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * - temp); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * + temp)); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * + temp)); indx++; col++; - red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]); - blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1])); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1])); } if(cc1 & 1) { // width of tile is odd float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]); - red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * - temp); - blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * - temp); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * + temp)); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * + temp)); } } else { for (; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++) { - red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]); - blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1])); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1])); indx++; col++; float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]); - red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * - temp); - blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * - temp); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) * + temp)); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) * + temp)); } if(cc1 & 1) { // width of tile is odd - red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]); - blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]); + red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1])); + blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1])); } } @@ -1568,13 +1568,13 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, c #ifdef __SSE2__ for (; cc < cc1 - 19; cc += 4) { - STVFU(green[row][cc + left], LVF(rgbgreen[rr * ts + cc]) * c65535v); + STVFU(green[row][cc + left], vmaxf(LVF(rgbgreen[rr * ts + cc]) * c65535v, ZEROV)); } #endif for (; cc < cc1 - 16; cc++) { - green[row][cc + left] = 65535.f * rgbgreen[rr * ts + cc]; + green[row][cc + left] = std::max(0.f, 65535.f * rgbgreen[rr * ts + cc]); } } diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 8639ea2e1..a3bab58a8 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1398,6 +1398,11 @@ Camera constants: "raw_crop": [ 4, 4, -4, -4 ] // full raw 6016x4016, Official 6000x4000 }, + { // Quality C, only raw crop + "make_model": "Leica SL2", + "raw_crop": [ 0, 0, 0, -18 ] // 18 rows at bottom are garbage + }, + { // Quality C "make_model": "LG mobile LG-H815", "dcraw_matrix": [ 5859,547,-1250,-6484,15547,547,-2422,5625,3906 ], // DNG D65 diff --git a/rtengine/canon_cr3_decoder.cc b/rtengine/canon_cr3_decoder.cc index 359243ed5..6274154cb 100644 --- a/rtengine/canon_cr3_decoder.cc +++ b/rtengine/canon_cr3_decoder.cc @@ -1,5 +1,25 @@ -/* -*- C++ -*- - * +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 RawTherapee development team + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +// Code adapted from ART +/* + * * This file is part of ART. * * ART is free software: you can redistribute it and/or modify @@ -16,15 +36,6 @@ * along with ART. If not, see . */ -#include -#include "dcraw.h" -#ifdef __GNUC__ // silence warning -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#endif - // Code adapted from libraw /* -*- C++ -*- * Copyright 2019 LibRaw LLC (info@libraw.org) @@ -40,570 +51,589 @@ */ +#include +#include +#include +#include +#include + +#include "dcraw.h" + +#include "rt_math.h" void DCraw::parse_canon_cr3() { - int err; - unsigned long long szAtomList; + strncpy(make, "Canon", sizeof(make)); + + unsigned long long szAtomList = ifp->size; short nesting = -1; - short nTrack = -1; - short TrackType; char AtomNameStack[128]; - strcpy(make, "Canon"); + unsigned short nTrack = 0; + short TrackType; - szAtomList = ifp->size; - err = parseCR3(0ULL, szAtomList, nesting, AtomNameStack, nTrack, TrackType); - if ((err == 0 || err == -14) && - nTrack >= 0) // no error, or too deep nesting + const int err = parseCR3(0, szAtomList, nesting, AtomNameStack, nTrack, TrackType); + + if (err == 0 || err == -14) { // no error, or too deep nesting selectCRXTrack(nTrack); + } } -#define LIBRAW_CRXTRACKS_MAXCOUNT RT_canon_CR3_data.CRXTRACKS_MAXCOUNT - -void DCraw::selectCRXTrack(short maxTrack) +void DCraw::selectCRXTrack(unsigned short maxTrack) { - if (maxTrack < 0) - return; - INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0; - uint32_t maxjpegbytes = 0; - memset(bitcounts, 0, sizeof(bitcounts)); - for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++) - { - CanonCR3Data::crx_data_header_t *d = &RT_canon_CR3_data.crx_header[i]; - if (d->MediaType == 1) // RAW - { - bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height); - if (bitcounts[i] > maxbitcount) - maxbitcount = bitcounts[i]; - } - else if (d->MediaType == 2) // JPEG - { - if (d->MediaSize > maxjpegbytes) - { - maxjpegbytes = d->MediaSize; - thumb_offset = d->MediaOffset; - thumb_length = d->MediaSize; - } - } - } - if (maxbitcount < 8) - return; - int framei = -1, framecnt = 0; - for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++) - { - if (bitcounts[i] == maxbitcount) - { - if (framecnt <= shot_select) - framei = i; - framecnt++; - } - } - is_raw = framecnt; - if (framei >= 0 && framei < LIBRAW_CRXTRACKS_MAXCOUNT) - { - CanonCR3Data::crx_data_header_t *d = - &RT_canon_CR3_data.crx_header[framei]; - data_offset = d->MediaOffset; - //data_size = d->MediaSize; - raw_width = d->f_width; - raw_height = d->f_height; - load_raw = &DCraw::crxLoadRaw; - switch (d->cfaLayout) - { - case 0: - filters = 0x94949494; - break; - case 1: - filters = 0x61616161; - break; - case 2: - filters = 0x49494949; - break; - case 3: - filters = 0x16161616; - break; - } + std::int64_t bitcounts[CanonCR3Data::CRXTRACKS_MAXCOUNT] = {}; + std::int64_t maxbitcount = 0; + std::uint32_t maxjpegbytes = 0; - RT_canon_CR3_data.crx_track_selected = framei; + for (unsigned int i = 0; i <= maxTrack && i < RT_canon_CR3_data.CRXTRACKS_MAXCOUNT; ++i) { + CanonCR3Data::crx_data_header_t* const d = &RT_canon_CR3_data.crx_header[i]; - int tiff_idx = -1; - INT64 tpixels = 0; - for (int i = 0; i < tiff_nifds; i++) - if (INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height) > tpixels) - { - tpixels = INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height); - tiff_idx = i; - } - if (tiff_idx >= 0) - flip = tiff_ifd[tiff_idx].flip; - } -} + if (d->MediaType == 1) { // RAW + bitcounts[i] = std::int64_t(d->nBits) * std::int64_t(d->f_width) * std::int64_t(d->f_height); -#define FORC4 for (c=0; c < 4; c++) - -#define bad_hdr \ - (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) || \ - (get4() != 0x00000008)) -int DCraw::parseCR3(unsigned long long oAtomList, - unsigned long long szAtomList, short &nesting, - char *AtomNameStack, short &nTrack, short &TrackType) -{ - /* - Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name - Atom size includes the length of the header and the size of all "contained" - Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located - after the Atom name if Atom size == 0, it is the last top-level Atom extending - to the end of the file Atom name is often a 4 symbol mnemonic, but can be a - 4-byte integer - */ - const char UIID_Canon[17] = - "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48"; - const char UIID_Preview[17] = - "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16"; - - /* - AtomType = 0 - unknown: "unk." - AtomType = 1 - container atom: "cont" - AtomType = 2 - leaf atom: "leaf" - AtomType = 3 - can be container, can be leaf: "both" - */ - const char sAtomeType[4][5] = {"unk.", "cont", "leaf", "both"}; - short AtomType; - static const struct - { - char AtomName[5]; - short AtomType; - } AtomNamesList[] = { - {"dinf", 1}, - {"edts", 1}, - {"fiin", 1}, - {"ipro", 1}, - {"iprp", 1}, - {"mdia", 1}, - {"meco", 1}, - {"mere", 1}, - {"mfra", 1}, - {"minf", 1}, - {"moof", 1}, - {"moov", 1}, - {"mvex", 1}, - {"paen", 1}, - {"schi", 1}, - {"sinf", 1}, - {"skip", 1}, - {"stbl", 1}, - {"stsd", 1}, - {"strk", 1}, - {"tapt", 1}, - {"traf", 1}, - {"trak", 1}, - - {"cdsc", 2}, - {"colr", 2}, - {"dimg", 2}, - // {"dref", 2}, - {"free", 2}, - {"frma", 2}, - {"ftyp", 2}, - {"hdlr", 2}, - {"hvcC", 2}, - {"iinf", 2}, - {"iloc", 2}, - {"infe", 2}, - {"ipco", 2}, - {"ipma", 2}, - {"iref", 2}, - {"irot", 2}, - {"ispe", 2}, - {"meta", 2}, - {"mvhd", 2}, - {"pitm", 2}, - {"pixi", 2}, - {"schm", 2}, - {"thmb", 2}, - {"tkhd", 2}, - {"url ", 2}, - {"urn ", 2}, - - {"CCTP", 1}, - {"CRAW", 1}, - - {"JPEG", 2}, - {"CDI1", 2}, - {"CMP1", 2}, - - {"CNCV", 2}, - {"CCDT", 2}, - {"CTBO", 2}, - {"CMT1", 2}, - {"CMT2", 2}, - {"CMT3", 2}, - {"CMT4", 2}, - {"THMB", 2}, - {"co64", 2}, - {"mdat", 2}, - {"mdhd", 2}, - {"nmhd", 2}, - {"stsc", 2}, - {"stsz", 2}, - {"stts", 2}, - {"vmhd", 2}, - - {"dref", 3}, - {"uuid", 3}, - }; - - const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"}; - - int c, err = 0; - - ushort tL; // Atom length represented in 4 or 8 bytes - char nmAtom[5]; // Atom name - unsigned long long oAtom, szAtom; // Atom offset and Atom size - unsigned long long oAtomContent, - szAtomContent; // offset and size of Atom content - unsigned long long lHdr; - - char UIID[16]; - uchar CMP1[36]; - char HandlerType[5], MediaFormatID[5]; - unsigned ImageWidth, ImageHeight; - long relpos_inDir, relpos_inBox; - unsigned szItem, Tag, lTag; - ushort tItem; - - nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0'; - strcpy(HandlerType, sHandlerType[0]); - ImageWidth = ImageHeight = 0U; - oAtom = oAtomList; - nesting++; - if (nesting > 31) - return -14; // too deep nesting - short s_order = order; - - while ((oAtom + 8ULL) <= (oAtomList + szAtomList)) - { - lHdr = 0ULL; - err = 0; - order = 0x4d4d; - fseek(ifp, oAtom, SEEK_SET); - szAtom = get4(); - FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp); - AtomNameStack[(nesting + 1) * 4] = '\0'; - tL = 4; - AtomType = 0; - - for (c = 0; c < sizeof AtomNamesList / sizeof *AtomNamesList; c++) - if (!strcmp(nmAtom, AtomNamesList[c].AtomName)) - { - AtomType = AtomNamesList[c].AtomType; - break; - } - - if (!AtomType) - { - err = 1; - } - - if (szAtom == 0ULL) - { - if (nesting != 0) - { - err = -2; - goto fin; - } - szAtom = szAtomList - oAtom; - oAtomContent = oAtom + 8ULL; - szAtomContent = szAtom - 8ULL; - } - else if (szAtom == 1ULL) - { - if ((oAtom + 16ULL) > (oAtomList + szAtomList)) - { - err = -3; - goto fin; - } - tL = 8; - szAtom = (((unsigned long long)get4()) << 32) | get4(); - oAtomContent = oAtom + 16ULL; - szAtomContent = szAtom - 16ULL; - } - else - { - oAtomContent = oAtom + 8ULL; - szAtomContent = szAtom - 8ULL; - } - - if (!strcmp(nmAtom, "trak")) - { - nTrack++; - TrackType = 0; - if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT) - break; - } - if (!strcmp(AtomNameStack, "moovuuid")) - { - lHdr = 16ULL; - fread(UIID, 1, lHdr, ifp); - if (!strncmp(UIID, UIID_Canon, lHdr)) - { - AtomType = 1; - } - else - fseek(ifp, -lHdr, SEEK_CUR); - } - else if (!strcmp(AtomNameStack, "moovuuidCCTP")) - { - lHdr = 12ULL; - } - else if (!strcmp(AtomNameStack, "moovuuidCMT1")) - { - short q_order = order; - order = get2(); - if ((tL != 4) || bad_hdr) - { - err = -4; - goto fin; - } - parse_tiff_ifd(oAtomContent); - order = q_order; - } - else if (!strcmp(AtomNameStack, "moovuuidCMT2")) - { - short q_order = order; - order = get2(); - if ((tL != 4) || bad_hdr) - { - err = -5; - goto fin; - } - parse_exif(oAtomContent); - order = q_order; - } - else if (!strcmp(AtomNameStack, "moovuuidCMT3")) - { - short q_order = order; - order = get2(); - if ((tL != 4) || bad_hdr) - { - err = -6; - goto fin; - } - fseek(ifp, -12L, SEEK_CUR); - parse_makernote(oAtomContent, 0); - order = q_order; - } - else if (!strcmp(AtomNameStack, "moovuuidCMT4")) - { - short q_order = order; - order = get2(); - if ((tL != 4) || bad_hdr) - { - err = -6; - goto fin; - } - INT64 off = ftell(ifp); - parse_gps(oAtomContent); - fseek(ifp, off, SEEK_SET); -// parse_gps_libraw(oAtomContent); - order = q_order; - } - else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr")) - { - fseek(ifp, 8L, SEEK_CUR); - FORC4 HandlerType[c] = fgetc(ifp); - for (c = 1; c < sizeof sHandlerType / sizeof *sHandlerType; c++) - if (!strcmp(HandlerType, sHandlerType[c])) - { - TrackType = c; - break; - } - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd")) - { - if (szAtomContent >= 16) - { - fseek(ifp, 12L, SEEK_CUR); - lHdr = 8; - } - else - { - err = -7; - goto fin; - } - FORC4 MediaFormatID[c] = fgetc(ifp); - if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW"))) - { - if (szAtomContent >= 44) - fseek(ifp, 24L, SEEK_CUR); - else - { - err = -8; - goto fin; - } - } - else - { - AtomType = 2; // only continue for CRAW - lHdr = 0; - } -#define current_track RT_canon_CR3_data.crx_header[nTrack] - - ImageWidth = get2(); - ImageHeight = get2(); - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW")) - { - lHdr = 82; - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1")) - { - if (szAtomContent >= 40) - fread(CMP1, 1, 36, ifp); - else - { - err = -7; - goto fin; - } - if (!crxParseImageHeader(CMP1, nTrack)) - current_track.MediaType = 1; - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG")) - { - current_track.MediaType = 2; - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz")) - { - if (szAtomContent == 12) - fseek(ifp, 4L, SEEK_CUR); - else if (szAtomContent == 16) - fseek(ifp, 12L, SEEK_CUR); - else - { - err = -9; - goto fin; - } - current_track.MediaSize = get4(); - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64")) - { - if (szAtomContent == 16) - fseek(ifp, 8L, SEEK_CUR); - else - { - err = -10; - goto fin; - } - current_track.MediaOffset = (((unsigned long long)get4()) << 32) | get4(); - } - - if (current_track.MediaSize && current_track.MediaOffset && - ((oAtom + szAtom) >= (oAtomList + szAtomList)) && - !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20)) - { - if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD"))) - { - order = 0x4949; - relpos_inDir = 0L; - while (relpos_inDir + 6 < current_track.MediaSize) - { - fseek(ifp, current_track.MediaOffset + relpos_inDir, SEEK_SET); - szItem = get4(); - tItem = get2(); - if ((relpos_inDir + szItem) > current_track.MediaSize) - { - err = -11; - goto fin; - } - if ((tItem == 7) || (tItem == 8) || (tItem == 9)) - { - relpos_inBox = relpos_inDir + 12L; - while (relpos_inBox + 8 < relpos_inDir + szItem) - { - fseek(ifp, current_track.MediaOffset + relpos_inBox, SEEK_SET); - lTag = get4(); - Tag = get4(); - if (lTag < 8) - { - err = -12; - goto fin; - } - else if ((relpos_inBox + lTag) > (relpos_inDir + szItem)) - { - err = -11; - goto fin; - } - if ((Tag == 0x927c) && ((tItem == 7) || (tItem == 8))) - { - fseek(ifp, current_track.MediaOffset + relpos_inBox + 8L, - SEEK_SET); - short q_order = order; - order = get2(); - if (bad_hdr) - { - err = -13; - goto fin; - } - fseek(ifp, -8L, SEEK_CUR); - RT_canon_CR3_data.CR3_CTMDtag = 1; - parse_makernote(current_track.MediaOffset + relpos_inBox + 8, - 0); - RT_canon_CR3_data.CR3_CTMDtag = 0; - order = q_order; - } - relpos_inBox += lTag; + if (bitcounts[i] > maxbitcount) { + maxbitcount = bitcounts[i]; + } + } else if (d->MediaType == 2) { // JPEG + if (d->MediaSize > maxjpegbytes) { + maxjpegbytes = d->MediaSize; + thumb_offset = d->MediaOffset; + thumb_length = d->MediaSize; } - } - relpos_inDir += szItem; } - order = 0x4d4d; - } } -#undef current_track - if (AtomType == 1) - { - err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting, - AtomNameStack, nTrack, TrackType); - if (err) - goto fin; + + if (maxbitcount < 8) { + return; + } + + bool has_framei = false; + unsigned int framei = 0; + unsigned int framecnt = 0; + + for (unsigned int i = 0; i <= maxTrack && i < RT_canon_CR3_data.CRXTRACKS_MAXCOUNT; ++i) { + if (bitcounts[i] == maxbitcount) { + if (framecnt <= shot_select) { + has_framei = true; + framei = i; + } + + framecnt++; + } + } + + is_raw = framecnt; + + if (has_framei) { + CanonCR3Data::crx_data_header_t* const d = &RT_canon_CR3_data.crx_header[framei]; + data_offset = d->MediaOffset; + // data_size = d->MediaSize; + raw_width = d->f_width; + raw_height = d->f_height; + load_raw = &DCraw::crxLoadRaw; + + switch (d->cfaLayout) { + case 0: { + filters = 0x94949494; + break; + } + + case 1: { + filters = 0x61616161; + break; + } + + case 2: { + filters = 0x49494949; + break; + } + + case 3: { + filters = 0x16161616; + break; + } + } + + RT_canon_CR3_data.crx_track_selected = framei; + + int tiff_idx = -1; + std::int64_t tpixels = 0; + + for (unsigned int i = 0; i < tiff_nifds; ++i) { + if (std::int64_t(tiff_ifd[i].height) * std::int64_t(tiff_ifd[i].height) > tpixels) { + tpixels = std::int64_t(tiff_ifd[i].height) * std::int64_t(tiff_ifd[i].height); + tiff_idx = i; + } + } + + if (tiff_idx >= 0) { + flip = tiff_ifd[tiff_idx].flip; + } + } +} + +int DCraw::parseCR3( + unsigned long long oAtomList, + unsigned long long szAtomList, + short& nesting, + char* AtomNameStack, + unsigned short& nTrack, + short& TrackType +) +{ + /* + Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name + Atom size includes the length of the header and the size of all "contained" + Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located + after the Atom name if Atom size == 0, it is the last top-level Atom extending + to the end of the file Atom name is often a 4 symbol mnemonic, but can be a + 4-byte integer + */ + const char UIID_Canon[17] = + "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48"; +// const char UIID_Preview[17] = +// "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16"; + + /* + AtomType = 0 - unknown: "unk." + AtomType = 1 - container atom: "cont" + AtomType = 2 - leaf atom: "leaf" + AtomType = 3 - can be container, can be leaf: "both" + */ +// const char sAtomeType[4][5] = {"unk.", "cont", "leaf", "both"}; + short AtomType; + static const struct { + char AtomName[5]; + short AtomType; + } AtomNamesList[] = { + {"dinf", 1}, + {"edts", 1}, + {"fiin", 1}, + {"ipro", 1}, + {"iprp", 1}, + {"mdia", 1}, + {"meco", 1}, + {"mere", 1}, + {"mfra", 1}, + {"minf", 1}, + {"moof", 1}, + {"moov", 1}, + {"mvex", 1}, + {"paen", 1}, + {"schi", 1}, + {"sinf", 1}, + {"skip", 1}, + {"stbl", 1}, + {"stsd", 1}, + {"strk", 1}, + {"tapt", 1}, + {"traf", 1}, + {"trak", 1}, + + {"cdsc", 2}, + {"colr", 2}, + {"dimg", 2}, + // {"dref", 2}, + {"free", 2}, + {"frma", 2}, + {"ftyp", 2}, + {"hdlr", 2}, + {"hvcC", 2}, + {"iinf", 2}, + {"iloc", 2}, + {"infe", 2}, + {"ipco", 2}, + {"ipma", 2}, + {"iref", 2}, + {"irot", 2}, + {"ispe", 2}, + {"meta", 2}, + {"mvhd", 2}, + {"pitm", 2}, + {"pixi", 2}, + {"schm", 2}, + {"thmb", 2}, + {"tkhd", 2}, + {"url ", 2}, + {"urn ", 2}, + + {"CCTP", 1}, + {"CRAW", 1}, + + {"JPEG", 2}, + {"CDI1", 2}, + {"CMP1", 2}, + + {"CNCV", 2}, + {"CCDT", 2}, + {"CTBO", 2}, + {"CMT1", 2}, + {"CMT2", 2}, + {"CMT3", 2}, + {"CMT4", 2}, + {"THMB", 2}, + {"co64", 2}, + {"mdat", 2}, + {"mdhd", 2}, + {"nmhd", 2}, + {"stsc", 2}, + {"stsz", 2}, + {"stts", 2}, + {"vmhd", 2}, + + {"dref", 3}, + {"uuid", 3}, + }; + + const char sHandlerType[5][5] = { + "unk.", + "soun", + "vide", + "hint", + "meta" + }; + + int err = 0; + + unsigned short tL; // Atom length represented in 4 or 8 bytes + char nmAtom[5]; // Atom name + unsigned long long oAtom; + unsigned long long szAtom; // Atom offset and Atom size + unsigned long long oAtomContent; + unsigned long long szAtomContent; // offset and size of Atom content + unsigned long long lHdr; + + char UIID[16]; + uchar CMP1[36]; + char HandlerType[5]; + char MediaFormatID[5]; +// unsigned int ImageWidth, ImageHeight; + unsigned long relpos_inDir; + unsigned long relpos_inBox; + unsigned int szItem; + unsigned int Tag; + unsigned int lTag; + unsigned short tItem; + + nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0'; + strncpy(HandlerType, sHandlerType[0], sizeof(HandlerType)); +// ImageWidth = ImageHeight = 0U; + oAtom = oAtomList; + ++nesting; + + if (nesting > 31) { + return -14; // too deep nesting + } + + short s_order = order; + + const auto is_bad_header = + [this]() -> bool + { + return + ( + order != 0x4D4D + && order != 0x4949 + ) + || get2() != 0x002A + || get4() != 0x00000008; + }; + + while ((oAtom + 8) <= (oAtomList + szAtomList)) { + lHdr = 0U; + err = 0; + order = 0x4D4D; + fseek(ifp, oAtom, SEEK_SET); + szAtom = get4(); + for (unsigned int c = 0; c < 4; ++c) { + nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp); + } + AtomNameStack[(nesting + 1) * 4] = '\0'; + tL = 4; + AtomType = 0; + + for (const auto& atom : AtomNamesList) { + if (!strcmp(nmAtom, atom.AtomName)) { + AtomType = atom.AtomType; + break; + } + } + + if (!AtomType) { + err = 1; + } + + if (szAtom == 0) { + if (nesting != 0) { + err = -2; + goto fin; + } + + szAtom = szAtomList - oAtom; + oAtomContent = oAtom + 8; + szAtomContent = szAtom - 8; + } else if (szAtom == 1) { + if ((oAtom + 16) > (oAtomList + szAtomList)) { + err = -3; + goto fin; + } + + tL = 8; + szAtom = (static_cast(get4()) << 32) | get4(); + oAtomContent = oAtom + 16; + szAtomContent = szAtom - 16; + } else { + oAtomContent = oAtom + 8; + szAtomContent = szAtom - 8; + } + + if (!strcmp(nmAtom, "trak")) { + nTrack++; + TrackType = 0; + + if (nTrack >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) { + break; + } + } + + if (!strcmp(AtomNameStack, "moovuuid")) { + lHdr = 16; + fread(UIID, 1, lHdr, ifp); + + if (!strncmp(UIID, UIID_Canon, lHdr)) { + AtomType = 1; + } else { + fseek(ifp, -lHdr, SEEK_CUR); + } + } else if (!strcmp(AtomNameStack, "moovuuidCCTP")) { + lHdr = 12; + } else if (!strcmp(AtomNameStack, "moovuuidCMT1")) { + const short q_order = order; + order = get2(); + + if (tL != 4 || is_bad_header()) { + err = -4; + goto fin; + } + + parse_tiff_ifd(oAtomContent); + order = q_order; + } else if (!strcmp(AtomNameStack, "moovuuidCMT2")) { + const short q_order = order; + order = get2(); + + if (tL != 4 || is_bad_header()) { + err = -5; + goto fin; + } + + parse_exif(oAtomContent); + order = q_order; + } else if (!strcmp(AtomNameStack, "moovuuidCMT3")) { + const short q_order = order; + order = get2(); + + if (tL != 4 || is_bad_header()) { + err = -6; + goto fin; + } + + fseek(ifp, -12L, SEEK_CUR); + parse_makernote(oAtomContent, 0); + order = q_order; + } else if (!strcmp(AtomNameStack, "moovuuidCMT4")) { + const short q_order = order; + order = get2(); + + if (tL != 4 || is_bad_header()) { + err = -6; + goto fin; + } + + const long off = ftell(ifp); + parse_gps(oAtomContent); + fseek(ifp, off, SEEK_SET); +// parse_gps_libraw(oAtomContent); + order = q_order; + } else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr")) { + fseek(ifp, 8, SEEK_CUR); + for (unsigned int c = 0; c < 4; ++c) { + HandlerType[c] = fgetc(ifp); + } + + for (unsigned int c = 1; c < sizeof(sHandlerType) / sizeof(*sHandlerType); ++c) { + if (!strcmp(HandlerType, sHandlerType[c])) { + TrackType = c; + break; + } + } + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd")) { + if (szAtomContent >= 16) { + fseek(ifp, 12, SEEK_CUR); + lHdr = 8; + } else { + err = -7; + goto fin; + } + + for (unsigned int c = 0; c < 4; ++c) { + MediaFormatID[c] = fgetc(ifp); + } + + if (TrackType == 2 && !strcmp(MediaFormatID, "CRAW")) { + if (szAtomContent >= 44) { + fseek(ifp, 24, SEEK_CUR); + } else { + err = -8; + goto fin; + } + } else { + AtomType = 2; // only continue for CRAW + lHdr = 0; + } + + /*ImageWidth = */ get2(); + /*ImageHeight = */ get2(); + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW")) { + lHdr = 82; + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1")) { + if (szAtomContent >= 40) { + fread(CMP1, 1, 36, ifp); + } else { + err = -7; + goto fin; + } + + if (crxParseImageHeader(CMP1, nTrack)) { + RT_canon_CR3_data.crx_header[nTrack].MediaType = 1; + } + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG")) { + RT_canon_CR3_data.crx_header[nTrack].MediaType = 2; + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz")) { + if (szAtomContent == 12) { + fseek(ifp, 4, SEEK_CUR); + } else if (szAtomContent == 16) { + fseek(ifp, 12, SEEK_CUR); + } else { + err = -9; + goto fin; + } + + RT_canon_CR3_data.crx_header[nTrack].MediaSize = get4(); + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64")) { + if (szAtomContent == 16) { + fseek(ifp, 8, SEEK_CUR); + } else { + err = -10; + goto fin; + } + + RT_canon_CR3_data.crx_header[nTrack].MediaOffset = (static_cast(get4()) << 32) | get4(); + } + + if ( + RT_canon_CR3_data.crx_header[nTrack].MediaSize + && RT_canon_CR3_data.crx_header[nTrack].MediaOffset + && oAtom + szAtom >= oAtomList + szAtomList + && !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20) + ) { + if (TrackType == 4 && !strcmp(MediaFormatID, "CTMD")) { + order = 0x4949; + relpos_inDir = 0; + + while (relpos_inDir + 6 < RT_canon_CR3_data.crx_header[nTrack].MediaSize) { + fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inDir, SEEK_SET); + szItem = get4(); + tItem = get2(); + + if ((relpos_inDir + szItem) > RT_canon_CR3_data.crx_header[nTrack].MediaSize) { + err = -11; + goto fin; + } + + if ( + tItem == 7 + || tItem == 8 + || tItem == 9 + ) { + relpos_inBox = relpos_inDir + 12; + + while (relpos_inBox + 8 < relpos_inDir + szItem) { + fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox, SEEK_SET); + lTag = get4(); + Tag = get4(); + + if (lTag < 8) { + err = -12; + goto fin; + } else if (relpos_inBox + lTag > relpos_inDir + szItem) { + err = -11; + goto fin; + } + + if ( + Tag == 0x927C + && ( + tItem == 7 + || tItem == 8 + ) + ) { + fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox + 8, SEEK_SET); + const short q_order = order; + order = get2(); + + if (is_bad_header()) { + err = -13; + goto fin; + } + + fseek(ifp, -8, SEEK_CUR); + RT_canon_CR3_data.CR3_CTMDtag = 1; + parse_makernote(RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox + 8, 0); + RT_canon_CR3_data.CR3_CTMDtag = 0; + order = q_order; + } + + relpos_inBox += lTag; + } + } + + relpos_inDir += szItem; + } + + order = 0x4D4D; + } + } + + if (AtomType == 1) { + err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting, AtomNameStack, nTrack, TrackType); + + if (err) { + goto fin; + } + } + + oAtom += szAtom; } - oAtom += szAtom; - } fin: - nesting--; - if (nesting >= 0) - AtomNameStack[nesting * 4] = '\0'; - order = s_order; - return err; + --nesting; + + if (nesting >= 0) { + AtomNameStack[nesting * 4] = '\0'; + } + + order = s_order; + return err; } -#undef bad_hdr +// ----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -#ifdef _abs -#undef _abs -#undef _min -#undef _constrain -#endif -#define _abs(x) (((x) ^ ((int32_t)(x) >> 31)) - ((int32_t)(x) >> 31)) -#define _min(a, b) ((a) < (b) ? (a) : (b)) -#define _constrain(x, l, u) ((x) < (l) ? (l) : ((x) > (u) ? (u) : (x))) - -#if defined(__clang__) || defined(__GNUG__) -#define libraw_inline inline __attribute__((always_inline)) -#elif defined(_MSC_VER) && _MSC_VER > 1400 -#define libraw_inline __forceinline -#else -#define libraw_inline inline -#endif - -namespace { - -static unsigned sgetn (int n, unsigned char *s) +namespace { - unsigned result = 0; + +unsigned int sgetn(int n, unsigned char* s) +{ + unsigned int result = 0; while (n-- > 0) { result = (result << 8) | (*s++); @@ -613,143 +643,147 @@ static unsigned sgetn (int n, unsigned char *s) } // this should be divisible by 4 -#define CRX_BUF_SIZE 0x10000 -#if !defined(_WIN32) || (defined (__GNUC__) && !defined(__INTRINSIC_SPECIAL__BitScanReverse)) +constexpr std::uint64_t CRX_BUF_SIZE = 0x10000; + +#if !defined (_WIN32) || (defined (__GNUC__) && !defined (__INTRINSIC_SPECIAL__BitScanReverse)) /* __INTRINSIC_SPECIAL__BitScanReverse found in MinGW32-W64 v7.30 headers, may be there is a better solution? */ -typedef uint32_t DWORD; -typedef uint8_t byte; -libraw_inline void _BitScanReverse(DWORD *Index, unsigned long Mask) +inline void _BitScanReverse(std::uint32_t* Index, unsigned long Mask) { - *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask); + *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask); +} +std::uint32_t _byteswap_ulong(std::uint32_t x) +{ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return x; +#else + return __builtin_bswap32(x); +#endif } -#define _byteswap_ulong(x) __builtin_bswap32(x) #endif - -#define LIBRAW_EXCEPTION_IO_EOF std::exception() - struct LibRaw_abstract_datastream { - IMFILE *ifp; - - void lock() {} - void unlock() {} - void seek(int p, int how) { fseek(ifp, p, how); } + IMFILE* ifp; + + void lock() + { + } + void unlock() + { + } + void seek(long p, int how) + { + fseek(ifp, p, how); + } int read(void* dst, int es, int count) - { return fread(dst, es, count, ifp); } + { + return fread(dst, es, count, ifp); + } }; -struct CrxBitstream -{ - uint8_t mdatBuf[CRX_BUF_SIZE]; - uint64_t mdatSize; - uint64_t curBufOffset; - uint32_t curPos; - uint32_t curBufSize; - uint32_t bitData; - int32_t bitsLeft; - LibRaw_abstract_datastream *input; +struct CrxBitstream { + std::uint8_t mdatBuf[CRX_BUF_SIZE]; + std::uint64_t mdatSize; + std::uint64_t curBufOffset; + std::uint32_t curPos; + std::uint32_t curBufSize; + std::uint32_t bitData; + std::int32_t bitsLeft; + LibRaw_abstract_datastream* input; }; -struct CrxBandParam -{ - CrxBitstream bitStream; - int16_t subbandWidth; - int16_t subbandHeight; - int32_t roundedBitsMask; - int32_t roundedBits; - int16_t curLine; - int32_t *lineBuf0; - int32_t *lineBuf1; - int32_t *lineBuf2; - int32_t sParam; - int32_t kParam; - int32_t *paramData; - int32_t *nonProgrData; - int8_t supportsPartial; +struct CrxBandParam { + CrxBitstream bitStream; + std::int16_t subbandWidth; + std::int16_t subbandHeight; + std::int32_t roundedBitsMask; + std::int32_t roundedBits; + std::int16_t curLine; + std::int32_t* lineBuf0; + std::int32_t* lineBuf1; + std::int32_t* lineBuf2; + std::int32_t sParam; + std::int32_t kParam; + std::int32_t* paramData; + std::int32_t* nonProgrData; + bool supportsPartial; }; -struct CrxWaveletTransform -{ - int32_t *subband0Buf; - int32_t *subband1Buf; - int32_t *subband2Buf; - int32_t *subband3Buf; - int32_t *lineBuf[8]; - int16_t curLine; - int16_t curH; - int8_t fltTapH; - int16_t height; - int16_t width; +struct CrxWaveletTransform { + std::int32_t* subband0Buf; + std::int32_t* subband1Buf; + std::int32_t* subband2Buf; + std::int32_t* subband3Buf; + std::int32_t* lineBuf[8]; + std::int16_t curLine; + std::int16_t curH; + std::int8_t fltTapH; + std::int16_t height; + std::int16_t width; }; -struct CrxSubband -{ - CrxBandParam *bandParam; - uint64_t mdatOffset; - uint8_t *bandBuf; - int32_t bandSize; - uint64_t dataSize; - int8_t supportsPartial; - int32_t quantValue; - uint16_t width; - uint16_t height; - int32_t paramK; - int64_t dataOffset; +struct CrxSubband { + CrxBandParam* bandParam; + std::uint64_t mdatOffset; + std::uint8_t* bandBuf; + std::int32_t bandSize; + std::uint64_t dataSize; + bool supportsPartial; + std::int32_t quantValue; + std::uint16_t width; + std::uint16_t height; + std::int32_t paramK; + std::int64_t dataOffset; }; -struct CrxPlaneComp -{ - byte *compBuf; - CrxSubband *subBands; - CrxWaveletTransform *waveletTransform; - int8_t compNumber; - int64_t dataOffset; - int32_t compSize; - int8_t supportsPartial; - int32_t roundedBitsMask; - int8_t tileFlag; +struct CrxPlaneComp { + std::uint8_t* compBuf; + CrxSubband* subBands; + CrxWaveletTransform* waveletTransform; + std::int8_t compNumber; + std::int64_t dataOffset; + std::int32_t compSize; + bool supportsPartial; + std::int32_t roundedBitsMask; + std::int8_t tileFlag; }; -struct CrxTile -{ - CrxPlaneComp *comps; - int8_t tileFlag; - int8_t tileNumber; - int64_t dataOffset; - int32_t tileSize; - uint16_t width; - uint16_t height; +struct CrxTile { + CrxPlaneComp* comps; + std::int8_t tileFlag; + std::int8_t tileNumber; + std::int64_t dataOffset; + std::int32_t tileSize; + std::uint16_t width; + std::uint16_t height; }; -struct CrxImage -{ - uint8_t nPlanes; - uint16_t planeWidth; - uint16_t planeHeight; - uint8_t samplePrecision; - uint8_t subbandCount; - uint8_t levels; - uint8_t nBits; - uint8_t encType; - uint8_t tileCols; - uint8_t tileRows; - CrxTile *tiles; - uint64_t mdatOffset; - uint64_t mdatSize; - int16_t *outBufs[4]; // one per plane - int16_t *planeBuf; - LibRaw_abstract_datastream *input; +struct CrxImage { + std::uint8_t nPlanes; + std::uint16_t planeWidth; + std::uint16_t planeHeight; + std::uint8_t samplePrecision; + std::uint8_t subbandCount; + std::uint8_t levels; + std::uint8_t nBits; + std::uint8_t encType; + std::uint8_t tileCols; + std::uint8_t tileRows; + CrxTile* tiles; + std::uint64_t mdatOffset; + std::uint64_t mdatSize; + std::int16_t* outBufs[4]; // one per plane + std::int16_t* planeBuf; + LibRaw_abstract_datastream* input; }; -enum TileFlags -{ - E_HAS_TILES_ON_THE_RIGHT = 1, - E_HAS_TILES_ON_THE_LEFT = 2, - E_HAS_TILES_ON_THE_BOTTOM = 4, - E_HAS_TILES_ON_THE_TOP = 8 +enum TileFlags { + E_HAS_TILES_ON_THE_RIGHT = 1, + E_HAS_TILES_ON_THE_LEFT = 2, + E_HAS_TILES_ON_THE_BOTTOM = 4, + E_HAS_TILES_ON_THE_TOP = 8 }; -int32_t exCoefNumTbl[0x120] = { +const std::int32_t exCoefNumTbl[0x120] = { // level 1 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, @@ -766,2351 +800,2442 @@ int32_t exCoefNumTbl[0x120] = { 1, 1, 7, 7, 1, 1, 3, 3, 1, 1, 1, 1, 1, 0, 7, 6, 1, 0, 3, 2, 1, 0, 1, 0, 1, 2, 10, 10, 2, 2, 5, 4, 2, 1, 2, 1, 1, 1, 10, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, 1, 9, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, 0, 9, 8, 1, 1, 4, 3, 1, 1, 1, 1, 1, 2, - 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1}; + 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1 +}; -uint32_t JS[32] = {1, 1, 1, 1, 2, 2, 2, 2, - 4, 4, 4, 4, 8, 8, 8, 8, - 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, - 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000}; +const std::uint32_t JS[32] = { + 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0004, 0x0004, 0x0004, 0x0004, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0010, 0x0010, 0x0020, 0x0020, 0x0040, 0x0040, 0x0080, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 +}; -uint32_t J[32] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, - 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; +const std::uint32_t J[32] = { + 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x5, 0x5, 0x6, 0x6, + 0x7, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF +}; -static inline void crxFillBuffer(CrxBitstream *bitStrm) +inline void crxFillBuffer(CrxBitstream* bitStrm) { - if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize) - { - bitStrm->curPos = 0; - bitStrm->curBufOffset += bitStrm->curBufSize; + if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize) { + bitStrm->curPos = 0; + bitStrm->curBufOffset += bitStrm->curBufSize; #ifdef _OPENMP -#pragma omp critical + #pragma omp critical #endif - { + { #ifndef _OPENMP - bitStrm->input->lock(); + bitStrm->input->lock(); #endif - bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET); - bitStrm->curBufSize = bitStrm->input->read( - bitStrm->mdatBuf, 1, _min(bitStrm->mdatSize, CRX_BUF_SIZE)); + bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET); + bitStrm->curBufSize = bitStrm->input->read(bitStrm->mdatBuf, 1, std::min(bitStrm->mdatSize, CRX_BUF_SIZE)); #ifndef _OPENMP - bitStrm->input->unlock(); + bitStrm->input->unlock(); #endif - if (bitStrm->curBufSize < 1) // nothing read - throw LIBRAW_EXCEPTION_IO_EOF; - bitStrm->mdatSize -= bitStrm->curBufSize; - } - } -} -libraw_inline int crxBitstreamGetZeros(CrxBitstream *bitStrm) -{ - uint32_t bitData = bitStrm->bitData; - uint32_t nonZeroBit = 0; - uint64_t nextData = 0; - int32_t result = 0; - - if (bitStrm->bitData) - { - _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)bitStrm->bitData); - result = 31 - nonZeroBit; - bitStrm->bitData <<= 32 - nonZeroBit; - bitStrm->bitsLeft -= 32 - nonZeroBit; - } - else - { - uint32_t bitsLeft = bitStrm->bitsLeft; - while (1) - { - while (bitStrm->curPos + 4 <= bitStrm->curBufSize) - { - nextData = - _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos)); - bitStrm->curPos += 4; - crxFillBuffer(bitStrm); - if (nextData) - { - _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData); - result = bitsLeft + 31 - nonZeroBit; - bitStrm->bitData = nextData << (32 - nonZeroBit); - bitStrm->bitsLeft = nonZeroBit; - return result; - } - bitsLeft += 32; - } - if (bitStrm->curBufSize < bitStrm->curPos + 1) - break; // error - nextData = bitStrm->mdatBuf[bitStrm->curPos++]; - crxFillBuffer(bitStrm); - if (nextData) - break; - bitsLeft += 8; - } - _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData); - result = (uint32_t)(bitsLeft + 7 - nonZeroBit); - bitStrm->bitData = nextData << (32 - nonZeroBit); - bitStrm->bitsLeft = nonZeroBit; - } - return result; -} - -libraw_inline uint32_t crxBitstreamGetBits(CrxBitstream *bitStrm, int bits) -{ - int bitsLeft = bitStrm->bitsLeft; - uint32_t bitData = bitStrm->bitData; - uint32_t nextWord; - uint8_t nextByte; - uint32_t result; - - if (bitsLeft < bits) - { - // get them from stream - if (bitStrm->curPos + 4 <= bitStrm->curBufSize) - { - nextWord = - _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos)); - bitStrm->curPos += 4; - crxFillBuffer(bitStrm); - bitStrm->bitsLeft = 32 - (bits - bitsLeft); - result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits); - bitStrm->bitData = nextWord << (bits - bitsLeft); - return result; - } - // less than a word left - read byte at a time - do - { - if (bitStrm->curPos >= bitStrm->curBufSize) - break; // error - bitsLeft += 8; - nextByte = bitStrm->mdatBuf[bitStrm->curPos++]; - crxFillBuffer(bitStrm); - bitData |= nextByte << (32 - bitsLeft); - } while (bitsLeft < bits); - } - result = bitData >> (32 - bits); // 32-bits - bitStrm->bitData = bitData << bits; - bitStrm->bitsLeft = bitsLeft - bits; - return result; -} - -libraw_inline int crxPredictKParameter(int32_t prevK, int32_t bitCode, - int32_t maxVal = 0) -{ - int32_t newKParam = prevK - (bitCode < (1 << prevK >> 1)) + - ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5); - - return !maxVal || newKParam < maxVal ? newKParam : maxVal; -} - -libraw_inline void crxDecodeSymbolL1(CrxBandParam *param, - int32_t doMedianPrediction, - int32_t notEOL = 0) -{ - if (doMedianPrediction) - { - int32_t symb[4]; - - int32_t delta = param->lineBuf0[1] - param->lineBuf0[0]; - symb[2] = param->lineBuf1[0]; - symb[0] = symb[1] = delta + symb[2]; - symb[3] = param->lineBuf0[1]; - - param->lineBuf1[1] = - symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1) + - ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0))]; - } - else - param->lineBuf1[1] = param->lineBuf0[1]; - - // get next error symbol - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - - // add converted (+/-) error code to predicted value - param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); - - // for not end of the line - use one symbol ahead to estimate next K - if (notEOL) - { - int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1; - bitCode = (bitCode + _abs(nextDelta)) >> 1; - ++param->lineBuf0; - } - - // update K parameter - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - - ++param->lineBuf1; -} - -int crxDecodeLine(CrxBandParam *param) -{ - int length = param->subbandWidth; - - param->lineBuf1[0] = param->lineBuf0[1]; - for (; length > 1; --length) - { - if (param->lineBuf1[0] != param->lineBuf0[1] || - param->lineBuf1[0] != param->lineBuf0[2]) - { - crxDecodeSymbolL1(param, 1, 1); - } - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; - } - - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - if (nSyms > length) - return -1; - } - - length -= nSyms; - - // copy symbol nSyms times - param->lineBuf0 += nSyms; - - // copy symbol nSyms times - while (nSyms-- > 0) - { - param->lineBuf1[1] = param->lineBuf1[0]; - ++param->lineBuf1; - } - } - - if (length > 0) - crxDecodeSymbolL1(param, 0, (length > 1)); - } - } - - if (length == 1) - crxDecodeSymbolL1(param, 1, 0); - - param->lineBuf1[1] = param->lineBuf1[0] + 1; - - return 0; -} - -libraw_inline void crxDecodeSymbolL1Rounded(CrxBandParam *param, - int32_t doSym = 1, - int32_t doCode = 1) -{ - int32_t sym = param->lineBuf0[1]; - - if (doSym) - { - // calculate the next symbol gradient - int32_t symb[4]; - int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0]; - symb[2] = param->lineBuf1[0]; - symb[0] = symb[1] = deltaH + symb[2]; - symb[3] = param->lineBuf0[1]; - sym = - symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1) + - ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0))]; - } - - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - int32_t code = -(bitCode & 1) ^ (bitCode >> 1); - param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code >> 31) + sym; - - if (doCode) - { - if (param->lineBuf0[2] > param->lineBuf0[1]) - code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask - - 1) >> - param->roundedBits; - else - code = -( - (param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >> - param->roundedBits); - - param->kParam = crxPredictKParameter(param->kParam, - (bitCode + 2 * _abs(code)) >> 1, 15); - } - else - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - - ++param->lineBuf1; -} - -int crxDecodeLineRounded(CrxBandParam *param) -{ - int32_t valueReached = 0; - - param->lineBuf0[0] = param->lineBuf0[1]; - param->lineBuf1[0] = param->lineBuf0[1]; - int32_t length = param->subbandWidth; - - for (; length > 1; --length) - { - if (_abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask) - { - crxDecodeSymbolL1Rounded(param); - ++param->lineBuf0; - valueReached = 1; - } - else if (valueReached || _abs(param->lineBuf0[0] - param->lineBuf1[0]) > - param->roundedBitsMask) - { - crxDecodeSymbolL1Rounded(param); - ++param->lineBuf0; - valueReached = 0; - } - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; - } - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - } - if (nSyms > length) - return -1; - } - length -= nSyms; - - // copy symbol nSyms times - param->lineBuf0 += nSyms; - - // copy symbol nSyms times - while (nSyms-- > 0) - { - param->lineBuf1[1] = param->lineBuf1[0]; - ++param->lineBuf1; - } - - if (length > 1) - { - crxDecodeSymbolL1Rounded(param, 0); - ++param->lineBuf0; - valueReached = _abs(param->lineBuf0[1] - param->lineBuf0[0]) > - param->roundedBitsMask; - } - else if (length == 1) - crxDecodeSymbolL1Rounded(param, 0, 0); - } - } - if (length == 1) - crxDecodeSymbolL1Rounded(param, 1, 0); - - param->lineBuf1[1] = param->lineBuf1[0] + 1; - - return 0; -} - -int crxDecodeLineNoRefPrevLine(CrxBandParam *param) -{ - int32_t i = 0; - - for (; i < param->subbandWidth - 1; i++) - { - if (param->lineBuf0[i + 2] | param->lineBuf0[i + 1] | param->lineBuf1[i]) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode); - if (param->lineBuf2[i + 1] - param->kParam <= 1) - { - if (param->kParam >= 15) - param->kParam = 15; - } - else - ++param->kParam; - } - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - if (i != param->subbandWidth - 1) - { - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (i + nSyms > param->subbandWidth) - { - nSyms = param->subbandWidth - i; - break; + if (bitStrm->curBufSize < 1) { // nothing read + throw std::exception(); } - if (param->sParam < 31) - ++param->sParam; - if (i + nSyms == param->subbandWidth) - break; - } - if (i + nSyms < param->subbandWidth) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - } - if (i + nSyms > param->subbandWidth) - return -1; + + bitStrm->mdatSize -= bitStrm->curBufSize; } - } - else if (i > param->subbandWidth) - return -1; + } +} - if (nSyms > 0) - { - memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(int32_t)); - memset(param->lineBuf2 + i, 0, nSyms * sizeof(int32_t)); - i += nSyms; - } +inline int crxBitstreamGetZeros(CrxBitstream* bitStrm) +{ +// std::uint32_t bitData = bitStrm->bitData; + std::uint32_t nonZeroBit = 0; + std::uint64_t nextData = 0; + std::int32_t result = 0; - if (i >= param->subbandWidth - 1) - { - if (i == param->subbandWidth - 1) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) + if (bitStrm->bitData) { + _BitScanReverse(&nonZeroBit, bitStrm->bitData); + result = 31 - nonZeroBit; + bitStrm->bitData <<= 32 - nonZeroBit; + bitStrm->bitsLeft -= 32 - nonZeroBit; + } else { + std::uint32_t bitsLeft = bitStrm->bitsLeft; + + while (true) { + while (bitStrm->curPos + 4 <= bitStrm->curBufSize) { + nextData = _byteswap_ulong(*reinterpret_cast(bitStrm->mdatBuf + bitStrm->curPos)); + bitStrm->curPos += 4; + crxFillBuffer(bitStrm); + + if (nextData) { + _BitScanReverse(&nonZeroBit, static_cast(nextData)); + result = bitsLeft + 31 - nonZeroBit; + bitStrm->bitData = nextData << (32 - nonZeroBit); + bitStrm->bitsLeft = nonZeroBit; + return result; + } + + bitsLeft += 32; + } + + if (bitStrm->curBufSize < bitStrm->curPos + 1) { + break; // error + } + + nextData = bitStrm->mdatBuf[bitStrm->curPos++]; + crxFillBuffer(bitStrm); + + if (nextData) { + break; + } + + bitsLeft += 8; + } + + _BitScanReverse(&nonZeroBit, static_cast(nextData)); + result = static_cast(bitsLeft + 7 - nonZeroBit); + bitStrm->bitData = nextData << (32 - nonZeroBit); + bitStrm->bitsLeft = nonZeroBit; + } + + return result; +} + +inline std::uint32_t crxBitstreamGetBits(CrxBitstream* bitStrm, int bits) +{ + int bitsLeft = bitStrm->bitsLeft; + std::uint32_t bitData = bitStrm->bitData; + std::uint32_t nextWord; + std::uint8_t nextByte; + std::uint32_t result; + + if (bitsLeft < bits) { + // get them from stream + if (bitStrm->curPos + 4 <= bitStrm->curBufSize) { + nextWord = _byteswap_ulong(*reinterpret_cast(bitStrm->mdatBuf + bitStrm->curPos)); + bitStrm->curPos += 4; + crxFillBuffer(bitStrm); + bitStrm->bitsLeft = 32 - (bits - bitsLeft); + result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits); + bitStrm->bitData = nextWord << (bits - bitsLeft); + return result; + } + + // less than a word left - read byte at a time + do { + if (bitStrm->curPos >= bitStrm->curBufSize) { + break; // error + } + + bitsLeft += 8; + nextByte = bitStrm->mdatBuf[bitStrm->curPos++]; + crxFillBuffer(bitStrm); + bitData |= nextByte << (32 - bitsLeft); + } while (bitsLeft < bits); + } + + result = bitData >> (32 - bits); // 32-bits + bitStrm->bitData = bitData << bits; + bitStrm->bitsLeft = bitsLeft - bits; + return result; +} + +inline std::int32_t crxPredictKParameter(std::int32_t prevK, std::int32_t bitCode, std::int32_t maxVal = 0) +{ + const std::int32_t newKParam = + prevK + - (bitCode < (1 << prevK >> 1)) + + ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5); + + return + !maxVal || newKParam < maxVal + ? newKParam + : maxVal; +} + +inline void crxDecodeSymbolL1(CrxBandParam* param, bool doMedianPrediction, bool notEOL = false) +{ + if (doMedianPrediction) { + const std::int32_t delta = param->lineBuf0[1] - param->lineBuf0[0]; + const std::int32_t symb[4] = { + delta + param->lineBuf1[0], + delta + param->lineBuf1[0], + param->lineBuf1[0], + param->lineBuf0[1] + }; + + param->lineBuf1[1] = symb[ + (((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1) + + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0)) + ]; + } else { + param->lineBuf1[1] = param->lineBuf0[1]; + } + + // get next error symbol + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + // add converted (+/-) error code to predicted value + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + + // for not end of the line - use one symbol ahead to estimate next K + if (notEOL) { + const std::int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1; + bitCode = (bitCode + std::abs(nextDelta)) >> 1; + ++param->lineBuf0; + } + + // update K parameter + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + + ++param->lineBuf1; +} + +bool crxDecodeLine(CrxBandParam* param) +{ + int length = param->subbandWidth; + + param->lineBuf1[0] = param->lineBuf0[1]; + + for (; length > 1; --length) { + if (param->lineBuf1[0] != param->lineBuf0[1] || param->lineBuf1[0] != param->lineBuf0[2]) { + crxDecodeSymbolL1(param, true, true); + } else { + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + int nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + + if (nSyms > length) { + return false; + } + } + + length -= nSyms; + + // copy symbol nSyms times + param->lineBuf0 += nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + } + + if (length > 0) { + crxDecodeSymbolL1(param, false, length > 1); + } + } + } + + if (length == 1) { + crxDecodeSymbolL1(param, true, false); + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return true; +} + +inline void crxDecodeSymbolL1Rounded(CrxBandParam* param, bool doSym = true, bool doCode = true) +{ + std::int32_t sym = param->lineBuf0[1]; + + if (doSym) { + // calculate the next symbol gradient + const std::int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0]; + const std::int32_t symb[4] = { + deltaH + param->lineBuf1[0], + deltaH + param->lineBuf1[0], + param->lineBuf1[0], + param->lineBuf0[1] + }; + sym = symb[ + (((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1) + + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0)) + ]; + } + + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + std::int32_t code = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code < 0) + sym; + + if (doCode) { + if (param->lineBuf0[2] > param->lineBuf0[1]) { + code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask - 1) >> param->roundedBits; + } else { + code = -((param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >> param->roundedBits); + } + + param->kParam = crxPredictKParameter(param->kParam, (bitCode + 2 * std::abs(code)) >> 1, 15); + } else { + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } + + ++param->lineBuf1; +} + +bool crxDecodeLineRounded(CrxBandParam* param) +{ + bool valueReached = false; + + param->lineBuf0[0] = param->lineBuf0[1]; + param->lineBuf1[0] = param->lineBuf0[1]; + std::int32_t length = param->subbandWidth; + + for (; length > 1; --length) { + if (std::abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask) { + crxDecodeSymbolL1Rounded(param); + ++param->lineBuf0; + valueReached = true; + } else if (valueReached || std::abs(param->lineBuf0[0] - param->lineBuf1[0]) > param->roundedBitsMask) { + crxDecodeSymbolL1Rounded(param); + ++param->lineBuf0; + valueReached = false; + } else { + int nSyms = 0; + + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + } + + if (nSyms > length) { + return false; + } + } + + length -= nSyms; + + // copy symbol nSyms times + param->lineBuf0 += nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length > 1) { + crxDecodeSymbolL1Rounded(param, false); + ++param->lineBuf0; + valueReached = std::abs(param->lineBuf0[1] - param->lineBuf0[0]) > param->roundedBitsMask; + } else if (length == 1) { + crxDecodeSymbolL1Rounded(param, false, false); + } + } + } + + if (length == 1) { + crxDecodeSymbolL1Rounded(param, true, false); + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return true; +} + +bool crxDecodeLineNoRefPrevLine(CrxBandParam* param) +{ + std::int32_t i = 0; + + for (; i < param->subbandWidth - 1; ++i) { + if (param->lineBuf0[i + 2] || param->lineBuf0[i + 1] || param->lineBuf1[i]) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode); + + if (param->lineBuf2[i + 1] - param->kParam <= 1) { + if (param->kParam >= 15) { + param->kParam = 15; + } + } else { + ++param->kParam; + } + } else { + int nSyms = 0; + + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms = 1; + + if (i != param->subbandWidth - 1) { + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (i + nSyms > param->subbandWidth) { + nSyms = param->subbandWidth - i; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (i + nSyms == param->subbandWidth) { + break; + } + } + + if (i + nSyms < param->subbandWidth) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + } + + if (i + nSyms > param->subbandWidth) { + return false; + } + } + } else if (i > param->subbandWidth) { + return false; + } + + if (nSyms > 0) { + memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(std::int32_t)); + memset(param->lineBuf2 + i, 0, nSyms * sizeof(std::int32_t)); + i += nSyms; + } + + if (i >= param->subbandWidth - 1) { + if (i == param->subbandWidth - 1) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[i] = param->kParam; + } + + continue; + } else { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode); + + if (param->lineBuf2[i + 1] - param->kParam <= 1) { + if (param->kParam >= 15) { + param->kParam = 15; + } + } else { + ++param->kParam; + } + } + } + + param->lineBuf2[i] = param->kParam; + } + + if (i == param->subbandWidth - 1) { + std::int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - param->lineBuf2[i] = param->kParam; - } - continue; - } - else - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode); - if (param->lineBuf2[i + 1] - param->kParam <= 1) - { - if (param->kParam >= 15) - param->kParam = 15; - } - else - ++param->kParam; - } - } - param->lineBuf2[i] = param->kParam; - } - if (i == param->subbandWidth - 1) - { - int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - param->lineBuf2[i] = param->kParam; - } - - return 0; -} - -int crxDecodeTopLine(CrxBandParam *param) -{ - param->lineBuf1[0] = 0; - - int32_t length = param->subbandWidth; - - // read the line from bitstream - for (; length > 1; --length) - { - if (param->lineBuf1[0]) - param->lineBuf1[1] = param->lineBuf1[0]; - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; - } - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - if (nSyms > length) - return -1; + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); } - length -= nSyms; - - // copy symbol nSyms times - while (nSyms-- > 0) - { - param->lineBuf1[1] = param->lineBuf1[0]; - ++param->lineBuf1; - } - - if (length <= 0) - break; - } - - param->lineBuf1[1] = 0; + param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[i] = param->kParam; } - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - ++param->lineBuf1; - } - - if (length == 1) - { - param->lineBuf1[1] = param->lineBuf1[0]; - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - ++param->lineBuf1; - } - - param->lineBuf1[1] = param->lineBuf1[0] + 1; - - return 0; + return true; } -int crxDecodeTopLineRounded(CrxBandParam *param) +bool crxDecodeTopLine(CrxBandParam* param) { - param->lineBuf1[0] = 0; + param->lineBuf1[0] = 0; - int32_t length = param->subbandWidth; + std::int32_t length = param->subbandWidth; - // read the line from bitstream - for (; length > 1; --length) - { - if (_abs(param->lineBuf1[0]) > param->roundedBitsMask) - param->lineBuf1[1] = param->lineBuf1[0]; - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; + // read the line from bitstream + for (; length > 1; --length) { + if (param->lineBuf1[0]) { + param->lineBuf1[1] = param->lineBuf1[0]; + } else { + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + int nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + + if (nSyms > length) { + return false; + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length <= 0) { + break; + } + } + + param->lineBuf1[1] = 0; } - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - if (nSyms > length) - return -1; + + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); } - } - length -= nSyms; + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } - // copy symbol nSyms times - while (nSyms-- > 0) - { + if (length == 1) { param->lineBuf1[1] = param->lineBuf1[0]; + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); ++param->lineBuf1; - } - - if (length <= 0) - break; - - param->lineBuf1[1] = 0; } - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); + param->lineBuf1[1] = param->lineBuf1[0] + 1; - int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); - param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - ++param->lineBuf1; - } - - if (length == 1) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); - param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - ++param->lineBuf1; - } - - param->lineBuf1[1] = param->lineBuf1[0] + 1; - - return 0; + return true; } -int crxDecodeTopLineNoRefPrevLine(CrxBandParam *param) +bool crxDecodeTopLineRounded(CrxBandParam* param) { - param->lineBuf0[0] = 0; - param->lineBuf1[0] = 0; - int32_t length = param->subbandWidth; - for (; length > 1; --length) - { - if (param->lineBuf1[0]) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - } - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; - } - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - if (nSyms > length) - return -1; - } - } + param->lineBuf1[0] = 0; - length -= nSyms; + std::int32_t length = param->subbandWidth; - // copy symbol nSyms times - while (nSyms-- > 0) - { - param->lineBuf2[0] = 0; - param->lineBuf1[1] = 0; + // read the line from bitstream + for (; length > 1; --length) { + if (std::abs(param->lineBuf1[0]) > param->roundedBitsMask) { + param->lineBuf1[1] = param->lineBuf1[0]; + } else { + int nSyms = 0; + + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + + if (nSyms > length) { + return false; + } + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length <= 0) { + break; + } + + param->lineBuf1[1] = 0; + } + + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + const std::int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); ++param->lineBuf1; + } + + if (length == 1) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + const std::int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return true; +} + +bool crxDecodeTopLineNoRefPrevLine(CrxBandParam* param) +{ + param->lineBuf0[0] = 0; + param->lineBuf1[0] = 0; + std::int32_t length = param->subbandWidth; + + for (; length > 1; --length) { + if (param->lineBuf1[0]) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } else { + int nSyms = 0; + + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + + if (nSyms > length) { + return false; + } + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf2[0] = 0; + param->lineBuf1[1] = 0; + ++param->lineBuf1; + ++param->lineBuf2; + } + + if (length <= 0) { + break; + } + + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } + + param->lineBuf2[0] = param->kParam; ++param->lineBuf2; - } - - if (length <= 0) - break; - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; } - param->lineBuf2[0] = param->kParam; - ++param->lineBuf2; - ++param->lineBuf1; - } - if (length == 1) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - param->lineBuf2[0] = param->kParam; - ++param->lineBuf1; - } + if (length == 1) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - param->lineBuf1[1] = 0; - - return 0; -} - -int crxDecodeLine(CrxBandParam *param, uint8_t *bandBuf) -{ - if (!param || !bandBuf) - return -1; - if (param->curLine >= param->subbandHeight) - return -1; - - if (param->curLine == 0) - { - int32_t lineLength = param->subbandWidth + 2; - - param->sParam = 0; - param->kParam = 0; - if (param->supportsPartial) - { - if (param->roundedBitsMask <= 0) - { - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeTopLine(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - else - { - param->roundedBits = 1; - if (param->roundedBitsMask & ~1) - { - while (param->roundedBitsMask >> param->roundedBits) - ++param->roundedBits; + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); } - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeTopLineRounded(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } + + param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[0] = param->kParam; + ++param->lineBuf1; } - else - { - param->lineBuf2 = (int32_t *)param->nonProgrData; - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeTopLineNoRefPrevLine(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - } - else if (!param->supportsPartial) - { - int32_t lineLength = param->subbandWidth + 2; - param->lineBuf2 = (int32_t *)param->nonProgrData; - if (param->curLine & 1) - { - param->lineBuf1 = (int32_t *)param->paramData; - param->lineBuf0 = param->lineBuf1 + lineLength; - } - else - { - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - } - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeLineNoRefPrevLine(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - else if (param->roundedBitsMask <= 0) - { - int32_t lineLength = param->subbandWidth + 2; - if (param->curLine & 1) - { - param->lineBuf1 = (int32_t *)param->paramData; - param->lineBuf0 = param->lineBuf1 + lineLength; - } - else - { - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - } - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeLine(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - else - { - int32_t lineLength = param->subbandWidth + 2; - if (param->curLine & 1) - { - param->lineBuf1 = (int32_t *)param->paramData; - param->lineBuf0 = param->lineBuf1 + lineLength; - } - else - { - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - } - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeLineRounded(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - return 0; + + param->lineBuf1[1] = 0; + + return true; } -int crxDecodeLineWithIQuantization(CrxSubband *subband) +bool crxDecodeLine(CrxBandParam* param, std::uint8_t* bandBuf) { - int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48}; - - if (!subband->dataSize) - { - memset(subband->bandBuf, 0, subband->bandSize); - return 0; - } - - if (subband->supportsPartial) - { - uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream); - if (bitCode >= 23) - bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8); - else if (subband->paramK) - bitCode = - crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) | - (bitCode << subband->paramK); - - subband->quantValue += - -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer - subband->paramK = crxPredictKParameter(subband->paramK, bitCode); - if (subband->paramK > 7) - return -1; - } - if (crxDecodeLine(subband->bandParam, subband->bandBuf)) - return -1; - - if (subband->width <= 0) - return 0LL; - - // update subband buffers - int32_t *bandBuf = (int32_t *)subband->bandBuf; - int32_t qScale = - q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6); - if (subband->quantValue / 6 >= 6) - qScale = q_step_tbl[subband->quantValue % 6] * - (1 << (subband->quantValue / 6 + 26)); - - if (qScale != 1) - for (int32_t i = 0; i < subband->width; i++) - bandBuf[i] *= qScale; - - return 0; -} - -void crxHorizontal53(int32_t *lineBufLA, int32_t *lineBufLB, - CrxWaveletTransform *wavelet, uint32_t tileFlag) -{ - int32_t *band0Buf = wavelet->subband0Buf; - int32_t *band1Buf = wavelet->subband1Buf; - int32_t *band2Buf = wavelet->subband2Buf; - int32_t *band3Buf = wavelet->subband3Buf; - - if (wavelet->width <= 1) - { - lineBufLA[0] = band0Buf[0]; - lineBufLB[0] = band2Buf[0]; - } - else - { - if (tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - ++band1Buf; - ++band3Buf; + if (!param || !bandBuf) { + return false; } - else - { - lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + + if (param->curLine >= param->subbandHeight) { + return false; } - ++band0Buf; - ++band2Buf; - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1); - lineBufLA[2] = delta; + if (param->curLine == 0) { + const std::int32_t lineLength = param->subbandWidth + 2; - delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1); - lineBufLB[2] = delta; + param->sParam = 0; + param->kParam = 0; - ++band0Buf; - ++band1Buf; - ++band2Buf; - ++band3Buf; - lineBufLA += 2; - lineBufLB += 2; - } - if (tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1); + if (param->supportsPartial) { + if (param->roundedBitsMask <= 0) { + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + const std::int32_t* const lineBuf = param->lineBuf1 + 1; - int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1); + if (!crxDecodeTopLine(param)) { + return false; + } - if (wavelet->width & 1) - { - lineBufLA[2] = deltaA; - lineBufLB[2] = deltaB; - } - } - else if (wavelet->width & 1) - { - lineBufLA[1] = - band1Buf[0] + - ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1); - lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } else { + param->roundedBits = 1; - lineBufLB[1] = - band3Buf[0] + - ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1); - lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - } - else - { - lineBufLA[1] = lineBufLA[0] + band1Buf[0]; - lineBufLB[1] = lineBufLB[0] + band3Buf[0]; - } - } -} + if (param->roundedBitsMask & ~1) { + while (param->roundedBitsMask >> param->roundedBits) { + ++param->roundedBits; + } + } -int32_t *crxIdwt53FilterGetLine(CrxPlaneComp *comp, int32_t level) -{ - int32_t *result = comp->waveletTransform[level] - .lineBuf[(comp->waveletTransform[level].fltTapH - - comp->waveletTransform[level].curH + 5) % - 5 + - 3]; - comp->waveletTransform[level].curH--; - return result; -} + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + const std::int32_t* const lineBuf = param->lineBuf1 + 1; -int crxIdwt53FilterDecode(CrxPlaneComp *comp, int32_t level) -{ - if (comp->waveletTransform[level].curH) - return 0; + if (!crxDecodeTopLineRounded(param)) { + return false; + } - CrxSubband *sband = comp->subBands + 3 * level; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } + } else { + param->lineBuf2 = param->nonProgrData; + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + const std::int32_t* const lineBuf = param->lineBuf1 + 1; - if (comp->waveletTransform[level].height - 3 <= - comp->waveletTransform[level].curLine && - !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) - { - if (comp->waveletTransform[level].height & 1) - { - if (level) - { - if (crxIdwt53FilterDecode(comp, level - 1)) - return -1; - } - else if (crxDecodeLineWithIQuantization(sband)) - return -1; + if (!crxDecodeTopLineNoRefPrevLine(param)) { + return false; + } - if (crxDecodeLineWithIQuantization(sband + 1)) - return -1; - } - } - else - { - if (level) - { - if (crxIdwt53FilterDecode(comp, level - 1)) - return -1; - } - else if (crxDecodeLineWithIQuantization(sband)) // LL band - return -1; - - if (crxDecodeLineWithIQuantization(sband + 1) || // HL band - crxDecodeLineWithIQuantization(sband + 2) || // LH band - crxDecodeLineWithIQuantization(sband + 3)) // HH band - return -1; - } - - return 0; -} - -int crxIdwt53FilterTransform(CrxPlaneComp *comp, uint32_t level) -{ - CrxWaveletTransform *wavelet = comp->waveletTransform + level; - - if (wavelet->curH) - return 0; - - if (wavelet->curLine >= wavelet->height - 3) - { - if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) - { - if (wavelet->height & 1) - { - if (level) - { - if (!wavelet[-1].curH) - if (crxIdwt53FilterTransform(comp, level - 1)) - return -1; - wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; } - int32_t *band0Buf = wavelet->subband0Buf; - int32_t *band1Buf = wavelet->subband1Buf; - int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; - int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; - int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; + } else if (!param->supportsPartial) { + const std::int32_t lineLength = param->subbandWidth + 2; + param->lineBuf2 = param->nonProgrData; + + if (param->curLine & 1) { + param->lineBuf1 = param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } else { + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + + const std::int32_t* const lineBuf = param->lineBuf1 + 1; + + if (!crxDecodeLineNoRefPrevLine(param)) { + return false; + } + + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } else if (param->roundedBitsMask <= 0) { + const std::int32_t lineLength = param->subbandWidth + 2; + + if (param->curLine & 1) { + param->lineBuf1 = param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } else { + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + + const std::int32_t* const lineBuf = param->lineBuf1 + 1; + + if (!crxDecodeLine(param)) { + return false; + } + + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } else { + const std::int32_t lineLength = param->subbandWidth + 2; + + if (param->curLine & 1) { + param->lineBuf1 = param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } else { + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + + const std::int32_t* const lineBuf = param->lineBuf1 + 1; + + if (!crxDecodeLineRounded(param)) { + return false; + } + + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } + + return true; +} + +bool crxDecodeLineWithIQuantization(CrxSubband* subband) +{ + constexpr std::int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48}; + + if (!subband->dataSize) { + memset(subband->bandBuf, 0, subband->bandSize); + return true; + } + + if (subband->supportsPartial) { + std::uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream); + + if (bitCode >= 23) { + bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8); + } else if (subband->paramK) { + bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) | (bitCode << subband->paramK); + } + + subband->quantValue += -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer + subband->paramK = crxPredictKParameter(subband->paramK, bitCode); + + if (subband->paramK > 7) { + return false; + } + } + + if (!crxDecodeLine(subband->bandParam, subband->bandBuf)) { + return false; + } + + if (subband->width == 0) { + return true; + } + + // update subband buffers + std::int32_t* const bandBuf = reinterpret_cast(subband->bandBuf); + std::int32_t qScale = q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6); + + if (subband->quantValue / 6 >= 6) { + qScale = q_step_tbl[subband->quantValue % 6] * (1 << (subband->quantValue / 6 + 26)); + } + + if (qScale != 1) { + for (std::int32_t i = 0; i < subband->width; ++i) { + bandBuf[i] *= qScale; + } + } + + return true; +} + +void crxHorizontal53( + std::int32_t* lineBufLA, + std::int32_t* lineBufLB, + CrxWaveletTransform* wavelet, + std::uint32_t tileFlag +) +{ + std::int32_t* band0Buf = wavelet->subband0Buf; + std::int32_t* band1Buf = wavelet->subband1Buf; + std::int32_t* band2Buf = wavelet->subband2Buf; + std::int32_t* band3Buf = wavelet->subband3Buf; + + if (wavelet->width <= 1) { + lineBufLA[0] = band0Buf[0]; + lineBufLB[0] = band2Buf[0]; + } else { + if (tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band1Buf; + ++band3Buf; + } else { + lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + + ++band0Buf; + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1); + lineBufLA[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1); + lineBufLB[2] = delta; + + ++band0Buf; + ++band1Buf; + ++band2Buf; + ++band3Buf; + lineBufLA += 2; + lineBufLB += 2; + } + + if (tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1); + + const std::int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1); + + if (wavelet->width & 1) { + lineBufLA[2] = deltaA; + lineBufLB[2] = deltaB; + } + } else if (wavelet->width & 1) { + lineBufLA[1] = band1Buf[0] + ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1); + lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + + lineBufLB[1] = band3Buf[0] + ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1); + lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } else { + lineBufLA[1] = lineBufLA[0] + band1Buf[0]; + lineBufLB[1] = lineBufLB[0] + band3Buf[0]; + } + } +} + +std::int32_t* crxIdwt53FilterGetLine(CrxPlaneComp* comp, std::int32_t level) +{ + std::int32_t* const result = comp->waveletTransform[level].lineBuf[ + (comp->waveletTransform[level].fltTapH - comp->waveletTransform[level].curH + 5) % 5 + 3 + ]; + --comp->waveletTransform[level].curH; + return result; +} + +bool crxIdwt53FilterDecode(CrxPlaneComp* comp, std::int32_t level) +{ + if (comp->waveletTransform[level].curH) { + return true; + } + + CrxSubband* const sband = comp->subBands + 3 * level; + + if (comp->waveletTransform[level].height - 3 <= comp->waveletTransform[level].curLine && !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) { + if (comp->waveletTransform[level].height & 1) { + if (level) { + if (!crxIdwt53FilterDecode(comp, level - 1)) { + return false; + } + } else if (!crxDecodeLineWithIQuantization(sband)) { + return false; + } + + if (!crxDecodeLineWithIQuantization(sband + 1)) { + return false; + } + } + } else { + if (level) { + if (!crxIdwt53FilterDecode(comp, level - 1)) { + return false; + } + } else if (!crxDecodeLineWithIQuantization(sband)) { // LL band + return false; + } + + if ( + !crxDecodeLineWithIQuantization(sband + 1) // HL band + || !crxDecodeLineWithIQuantization(sband + 2) // LH band + || !crxDecodeLineWithIQuantization(sband + 3) // HH band + ) { + return false; + } + } + + return true; +} + +bool crxIdwt53FilterTransform(CrxPlaneComp* comp, std::uint32_t level) +{ + CrxWaveletTransform* const wavelet = comp->waveletTransform + level; + + if (wavelet->curH) { + return true; + } + + if (wavelet->curLine >= wavelet->height - 3) { + if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) { + if (wavelet->height & 1) { + if (level) { + if (!wavelet[-1].curH) { + if (!crxIdwt53FilterTransform(comp, level - 1)) { + return false; + } + } + + wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + } + + const std::int32_t* band0Buf = wavelet->subband0Buf; + const std::int32_t* band1Buf = wavelet->subband1Buf; + const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + std::int32_t* const lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; + + std::int32_t* lineBufL0 = wavelet->lineBuf[0]; + std::int32_t* lineBufL1 = wavelet->lineBuf[1]; + wavelet->lineBuf[1] = wavelet->lineBuf[2]; + wavelet->lineBuf[2] = lineBufL1; + + // process L bands + if (wavelet->width <= 1) { + lineBufL0[0] = band0Buf[0]; + } else { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + ++band1Buf; + } else { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + } + + ++band0Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + lineBufL0[2] = delta; + ++band0Buf; + ++band1Buf; + lineBufL0 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + + if (wavelet->width & 1) { + lineBufL0[2] = delta; + } + } else if (wavelet->width & 1) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + lineBufL0[2] = delta; + } else { + lineBufL0[1] = band1Buf[0] + lineBufL0[0]; + } + } + + // process H bands + lineBufL0 = wavelet->lineBuf[0]; + lineBufL1 = wavelet->lineBuf[1]; + + for (std::int32_t i = 0; i < wavelet->width; ++i) { + const std::int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1); + lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); + lineBufH2[i] = delta; + } + + wavelet->curH += 3; + wavelet->curLine += 3; + wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; + } else { + std::int32_t* const lineBufL2 = wavelet->lineBuf[2]; + const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + wavelet->lineBuf[1] = lineBufL2; + wavelet->lineBuf[2] = wavelet->lineBuf[1]; + + for (std::int32_t i = 0; i < wavelet->width; ++i) { + lineBufH1[i] = lineBufH0[i] + lineBufL2[i]; + } + + wavelet->curH += 2; + wavelet->curLine += 2; + wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; + } + } + } else { + if (level) { + if (!wavelet[-1].curH && !crxIdwt53FilterTransform(comp, level - 1)) { + return false; + } + + wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + } + + const std::int32_t* band0Buf = wavelet->subband0Buf; + const std::int32_t* band1Buf = wavelet->subband1Buf; + const std::int32_t* band2Buf = wavelet->subband2Buf; + const std::int32_t* band3Buf = wavelet->subband3Buf; + + std::int32_t* lineBufL0 = wavelet->lineBuf[0]; + std::int32_t* lineBufL1 = wavelet->lineBuf[1]; + const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + std::int32_t* const lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; - int32_t *lineBufL0 = wavelet->lineBuf[0]; - int32_t *lineBufL1 = wavelet->lineBuf[1]; wavelet->lineBuf[1] = wavelet->lineBuf[2]; wavelet->lineBuf[2] = lineBufL1; // process L bands - if (wavelet->width <= 1) - { - lineBufL0[0] = band0Buf[0]; - } - else - { - if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - ++band1Buf; - } - else - { - lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - } - ++band0Buf; - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = - band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); - lineBufL0[2] = delta; + if (wavelet->width <= 1) { + lineBufL0[0] = band0Buf[0]; + lineBufL1[0] = band2Buf[0]; + } else { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band1Buf; + ++band3Buf; + } else { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + ++band0Buf; - ++band1Buf; - lineBufL0 += 2; - } - if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t delta = - band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); - if (wavelet->width & 1) - lineBufL0[2] = delta; - } - else if (wavelet->width & 1) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); - lineBufL0[2] = delta; - } - else - lineBufL0[1] = band1Buf[0] + lineBufL0[0]; + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); + lineBufL0[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); + lineBufL1[2] = delta; + + ++band0Buf; + ++band1Buf; + ++band2Buf; + ++band3Buf; + lineBufL0 += 2; + lineBufL1 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1); + + const std::int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1); + + if (wavelet->width & 1) { + lineBufL0[2] = deltaA; + lineBufL1[2] = deltaB; + } + } else if (wavelet->width & 1) { + std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); + lineBufL0[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); + lineBufL1[2] = delta; + } else { + lineBufL0[1] = lineBufL0[0] + band1Buf[0]; + lineBufL1[1] = lineBufL1[0] + band3Buf[0]; + } } // process H bands lineBufL0 = wavelet->lineBuf[0]; lineBufL1 = wavelet->lineBuf[1]; - for (int32_t i = 0; i < wavelet->width; i++) - { - int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1); - lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); - lineBufH2[i] = delta; + const std::int32_t* lineBufL2 = wavelet->lineBuf[2]; + + for (std::int32_t i = 0; i < wavelet->width; ++i) { + const std::int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2); + lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); + lineBufH2[i] = delta; } - wavelet->curH += 3; - wavelet->curLine += 3; - wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; - } - else - { - int32_t *lineBufL2 = wavelet->lineBuf[2]; - int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; - int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; - wavelet->lineBuf[1] = lineBufL2; - wavelet->lineBuf[2] = wavelet->lineBuf[1]; - for (int32_t i = 0; i < wavelet->width; i++) - lineBufH1[i] = lineBufH0[i] + lineBufL2[i]; - - wavelet->curH += 2; - wavelet->curLine += 2; - wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; - } - } - } - else - { - if (level) - { - if (!wavelet[-1].curH && crxIdwt53FilterTransform(comp, level - 1)) - return -1; - wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); - } - - int32_t *band0Buf = wavelet->subband0Buf; - int32_t *band1Buf = wavelet->subband1Buf; - int32_t *band2Buf = wavelet->subband2Buf; - int32_t *band3Buf = wavelet->subband3Buf; - - int32_t *lineBufL0 = wavelet->lineBuf[0]; - int32_t *lineBufL1 = wavelet->lineBuf[1]; - int32_t *lineBufL2 = wavelet->lineBuf[2]; - int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; - int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; - int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; - - wavelet->lineBuf[1] = wavelet->lineBuf[2]; - wavelet->lineBuf[2] = lineBufL1; - - // process L bands - if (wavelet->width <= 1) - { - lineBufL0[0] = band0Buf[0]; - lineBufL1[0] = band2Buf[0]; - } - else - { - if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - ++band1Buf; - ++band3Buf; - } - else - { - lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - } - ++band0Buf; - ++band2Buf; - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); - lineBufL0[2] = delta; - - delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); - lineBufL1[2] = delta; - - ++band0Buf; - ++band1Buf; - ++band2Buf; - ++band3Buf; - lineBufL0 += 2; - lineBufL1 += 2; - } - if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1); - - int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1); - - if (wavelet->width & 1) - { - lineBufL0[2] = deltaA; - lineBufL1[2] = deltaB; + if (wavelet->curLine >= wavelet->height - 3 && (wavelet->height & 1)) { + wavelet->curH += 3; + wavelet->curLine += 3; + wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; + } else { + wavelet->curH += 2; + wavelet->curLine += 2; + wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; } - } - else if (wavelet->width & 1) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); - lineBufL0[2] = delta; - - delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); - lineBufL1[2] = delta; - } - else - { - lineBufL0[1] = lineBufL0[0] + band1Buf[0]; - lineBufL1[1] = lineBufL1[0] + band3Buf[0]; - } } - // process H bands - lineBufL0 = wavelet->lineBuf[0]; - lineBufL1 = wavelet->lineBuf[1]; - lineBufL2 = wavelet->lineBuf[2]; - for (int32_t i = 0; i < wavelet->width; i++) - { - int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2); - lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); - lineBufH2[i] = delta; - } - if (wavelet->curLine >= wavelet->height - 3 && wavelet->height & 1) - { - wavelet->curH += 3; - wavelet->curLine += 3; - wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; - } - else - { - wavelet->curH += 2; - wavelet->curLine += 2; - wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; - } - } - - return 0; + return true; } -int crxIdwt53FilterInitialize(CrxPlaneComp *comp, int32_t prevLevel) +bool crxIdwt53FilterInitialize(CrxPlaneComp* comp, std::int32_t prevLevel) { - if (prevLevel < 0) - return 0; + if (prevLevel < 0) { + return true; + } - for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1; - curLevel++, curBand += 3) - { - CrxWaveletTransform *wavelet = comp->waveletTransform + curLevel; - if (curLevel) - wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1); - else if (crxDecodeLineWithIQuantization(comp->subBands + curBand)) - return -1; + for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1; ++curLevel, curBand += 3) { + CrxWaveletTransform* const wavelet = comp->waveletTransform + curLevel; - int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; - if (wavelet->height > 1) - { - if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1) || - crxDecodeLineWithIQuantization(comp->subBands + curBand + 2) || - crxDecodeLineWithIQuantization(comp->subBands + curBand + 3)) - return -1; - - int32_t *lineBufL0 = wavelet->lineBuf[0]; - int32_t *lineBufL1 = wavelet->lineBuf[1]; - int32_t *lineBufL2 = wavelet->lineBuf[2]; - - if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP) - { - crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet, - comp->tileFlag); - if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 3) || - crxDecodeLineWithIQuantization(comp->subBands + curBand + 2)) - return -1; - - int32_t *band2Buf = wavelet->subband2Buf; - int32_t *band3Buf = wavelet->subband3Buf; - - // process L band - if (wavelet->width <= 1) - lineBufL2[0] = band2Buf[0]; - else - { - if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - ++band3Buf; - } - else - lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - - ++band2Buf; - - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = - band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); - lineBufL2[2] = delta; - - ++band2Buf; - ++band3Buf; - lineBufL2 += 2; - } - if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t delta = - band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); - if (wavelet->width & 1) - lineBufL2[2] = delta; - } - else if (wavelet->width & 1) - { - int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - - lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); - lineBufL2[2] = delta; - } - else - { - lineBufL2[1] = band3Buf[0] + lineBufL2[0]; - } + if (curLevel) { + wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1); + } else if (!crxDecodeLineWithIQuantization(comp->subBands + curBand)) { + return false; } - // process H band - for (int32_t i = 0; i < wavelet->width; i++) - lineBufH0[i] = - lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2); - } - else - { - crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet, - comp->tileFlag); - for (int i = 0; i < wavelet->width; i++) - lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1); - } - - if (crxIdwt53FilterDecode(comp, curLevel) || - crxIdwt53FilterTransform(comp, curLevel)) - return -1; - } - else - { - if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1)) - return -1; - - int32_t *band0Buf = wavelet->subband0Buf; - int32_t *band1Buf = wavelet->subband1Buf; - - // process H band - if (wavelet->width <= 1) - lineBufH0[0] = band0Buf[0]; - else - { - if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - ++band1Buf; - } - else - lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - - ++band0Buf; - - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); - lineBufH0[2] = delta; - - ++band0Buf; - ++band1Buf; - lineBufH0 += 2; - } - - if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); - lineBufH0[2] = delta; - } - else if (wavelet->width & 1) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); - lineBufH0[2] = delta; - } - else - { - lineBufH0[1] = band1Buf[0] + lineBufH0[0]; - } - } - ++wavelet->curLine; - ++wavelet->curH; - wavelet->fltTapH = (wavelet->fltTapH + 1) % 5; - } - } - - return 0; -} - -void crxFreeSubbandData(CrxImage *image, CrxPlaneComp *comp) -{ - if (comp->compBuf) - { - free(comp->compBuf); - comp->compBuf = 0; - } - - if (!comp->subBands) - return; - - for (int32_t i = 0; i < image->subbandCount; i++) - { - if (comp->subBands[i].bandParam) - { - free(comp->subBands[i].bandParam); - comp->subBands[i].bandParam = 0LL; - } - comp->subBands[i].bandBuf = 0; - comp->subBands[i].bandSize = 0; - } -} - -void crxConvertPlaneLine(CrxImage *img, int imageRow, int imageCol = 0, - int plane = 0, int32_t *lineData = 0, - int lineLength = 0) -{ - if (lineData) - { - uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol; - if (img->encType == 1) - { - int32_t maxVal = 1 << (img->nBits - 1); - int32_t minVal = -maxVal; - --maxVal; - for (int i = 0; i < lineLength; i++) - img->outBufs[plane][rawOffset + 2 * i] = - _constrain(lineData[i], minVal, maxVal); - } - else if (img->encType == 3) - { - // copy to intermediate planeBuf - rawOffset = plane * img->planeWidth * img->planeHeight + - img->planeWidth * imageRow + imageCol; - for (int i = 0; i < lineLength; i++) - img->planeBuf[rawOffset + i] = lineData[i]; - } - else if (img->nPlanes == 4) - { - int32_t median = 1 << (img->nBits - 1); - int32_t maxVal = (1 << img->nBits) - 1; - for (int i = 0; i < lineLength; i++) - img->outBufs[plane][rawOffset + 2 * i] = - _constrain(median + lineData[i], 0, maxVal); - } - else if (img->nPlanes == 1) - { - int32_t maxVal = (1 << img->nBits) - 1; - int32_t median = 1 << (img->nBits - 1); - rawOffset = img->planeWidth * imageRow + imageCol; - for (int i = 0; i < lineLength; i++) - img->outBufs[0][rawOffset + i] = - _constrain(median + lineData[i], 0, maxVal); - } - } - else if (img->encType == 3 && img->planeBuf) - { - int32_t planeSize = img->planeWidth * img->planeHeight; - int16_t *plane0 = img->planeBuf + imageRow * img->planeWidth; - int16_t *plane1 = plane0 + planeSize; - int16_t *plane2 = plane1 + planeSize; - int16_t *plane3 = plane2 + planeSize; - - int32_t median = 1 << (img->nBits - 1) << 10; - int32_t maxVal = (1 << img->nBits) - 1; - uint32_t rawLineOffset = 4 * img->planeWidth * imageRow; - - // for this stage - all except imageRow is ignored - for (int i = 0; i < img->planeWidth; i++) - { - int32_t gr = - median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i]; - int32_t val = 0; - if (gr < 0) - gr = -(((_abs(gr) + 512) >> 9) & ~1); - else - gr = ((_abs(gr) + 512) >> 9) & ~1; - - // Essentially R = round(median + P0 + 1.474*P3) - val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10; - img->outBufs[0][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); - // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3) - val = (plane2[i] + gr + 1) >> 1; - img->outBufs[1][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); - // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3) - val = (gr - plane2[i] + 1) >> 1; - img->outBufs[2][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); - // Essentially B = round(median + P0 + 1.881*P1) - val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10; - img->outBufs[3][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); - } - } -} - -int crxParamInit(CrxBandParam **param, uint64_t subbandMdatOffset, - uint64_t subbandDataSize, uint32_t subbandWidth, - uint32_t subbandHeight, int32_t supportsPartial, - uint32_t roundedBitsMask, LibRaw_abstract_datastream *input) -{ - int32_t progrDataSize = supportsPartial ? 0 : sizeof(int32_t) * subbandWidth; - int32_t paramLength = 2 * subbandWidth + 4; - uint8_t *paramBuf = (uint8_t *)calloc( - 1, sizeof(CrxBandParam) + sizeof(int32_t) * paramLength + progrDataSize); - - if (!paramBuf) - return -1; - - *param = (CrxBandParam *)paramBuf; - - paramBuf += sizeof(CrxBandParam); - - (*param)->paramData = (int32_t *)paramBuf; - (*param)->nonProgrData = - progrDataSize ? (*param)->paramData + paramLength : 0; - (*param)->subbandWidth = subbandWidth; - (*param)->subbandHeight = subbandHeight; - (*param)->roundedBits = 0; - (*param)->curLine = 0; - (*param)->roundedBitsMask = roundedBitsMask; - (*param)->supportsPartial = supportsPartial; - (*param)->bitStream.bitData = 0; - (*param)->bitStream.bitsLeft = 0; - (*param)->bitStream.mdatSize = subbandDataSize; - (*param)->bitStream.curPos = 0; - (*param)->bitStream.curBufSize = 0; - (*param)->bitStream.curBufOffset = subbandMdatOffset; - (*param)->bitStream.input = input; - - crxFillBuffer(&(*param)->bitStream); - - return 0; -} - -int crxSetupSubbandData(CrxImage *img, CrxPlaneComp *planeComp, - const CrxTile *tile, uint32_t mdatOffset) -{ - long compDataSize = 0; - long waveletDataOffset = 0; - long compCoeffDataOffset = 0; - int32_t toSubbands = 3 * img->levels + 1; - int32_t transformWidth = 0; - - CrxSubband *subbands = planeComp->subBands; - - // calculate sizes - for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) - { - subbands[subbandNum].bandSize = - subbands[subbandNum].width * sizeof(int32_t); // 4bytes - compDataSize += subbands[subbandNum].bandSize; - } - - if (img->levels) - { - int32_t encLevels = img->levels ? img->levels : 1; - waveletDataOffset = (compDataSize + 7) & ~7; - compDataSize = - (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7; - compCoeffDataOffset = compDataSize; - - // calc wavelet line buffer sizes (always at one level up from current) - for (int level = 0; level < img->levels; ++level) - if (level < img->levels - 1) - compDataSize += 8 * sizeof(int32_t) * - planeComp->subBands[3 * (level + 1) + 2].width; - else - compDataSize += 8 * sizeof(int32_t) * tile->width; - } - - // buffer allocation - planeComp->compBuf = (uint8_t *)malloc(compDataSize); - if (!planeComp->compBuf) - return -1; - - // subbands buffer and sizes initialisation - uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset; - uint8_t *subbandBuf = planeComp->compBuf; - - for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) - { - subbands[subbandNum].bandBuf = subbandBuf; - subbandBuf += subbands[subbandNum].bandSize; - subbands[subbandNum].mdatOffset = - subbandMdatOffset + subbands[subbandNum].dataOffset; - } - - // wavelet data initialisation - if (img->levels) - { - CrxWaveletTransform *waveletTransforms = - (CrxWaveletTransform *)(planeComp->compBuf + waveletDataOffset); - int32_t *paramData = (int32_t *)(planeComp->compBuf + compCoeffDataOffset); - - planeComp->waveletTransform = waveletTransforms; - waveletTransforms[0].subband0Buf = (int32_t *)subbands->bandBuf; - - for (int level = 0; level < img->levels; ++level) - { - int32_t band = 3 * level + 1; - - if (level >= img->levels - 1) - { - waveletTransforms[level].height = tile->height; - transformWidth = tile->width; - } - else - { - waveletTransforms[level].height = subbands[band + 3].height; - transformWidth = subbands[band + 4].width; - } - waveletTransforms[level].width = transformWidth; - waveletTransforms[level].lineBuf[0] = paramData; - waveletTransforms[level].lineBuf[1] = - waveletTransforms[level].lineBuf[0] + transformWidth; - waveletTransforms[level].lineBuf[2] = - waveletTransforms[level].lineBuf[1] + transformWidth; - waveletTransforms[level].lineBuf[3] = - waveletTransforms[level].lineBuf[2] + transformWidth; - waveletTransforms[level].lineBuf[4] = - waveletTransforms[level].lineBuf[3] + transformWidth; - waveletTransforms[level].lineBuf[5] = - waveletTransforms[level].lineBuf[4] + transformWidth; - waveletTransforms[level].lineBuf[6] = - waveletTransforms[level].lineBuf[5] + transformWidth; - waveletTransforms[level].lineBuf[7] = - waveletTransforms[level].lineBuf[6] + transformWidth; - waveletTransforms[level].curLine = 0; - waveletTransforms[level].curH = 0; - waveletTransforms[level].fltTapH = 0; - waveletTransforms[level].subband1Buf = (int32_t *)subbands[band].bandBuf; - waveletTransforms[level].subband2Buf = - (int32_t *)subbands[band + 1].bandBuf; - waveletTransforms[level].subband3Buf = - (int32_t *)subbands[band + 2].bandBuf; - - paramData = waveletTransforms[level].lineBuf[7] + transformWidth; - } - } - - // decoding params and bitstream initialisation - for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) - { - if (subbands[subbandNum].dataSize) - { - int32_t supportsPartial = 0; - uint32_t roundedBitsMask = 0; - - if (planeComp->supportsPartial && subbandNum == 0) - { - roundedBitsMask = planeComp->roundedBitsMask; - supportsPartial = 1; - } - if (crxParamInit(&subbands[subbandNum].bandParam, - subbands[subbandNum].mdatOffset, - subbands[subbandNum].dataSize, - subbands[subbandNum].width, subbands[subbandNum].height, - supportsPartial, roundedBitsMask, img->input)) - return -1; - } - } - - return 0; -} - -} // namespace - - -int DCraw::crxDecodePlane(void *p, uint32_t planeNumber) -{ - CrxImage *img = (CrxImage *)p; - int imageRow = 0; - for (int tRow = 0; tRow < img->tileRows; tRow++) - { - int imageCol = 0; - for (int tCol = 0; tCol < img->tileCols; tCol++) - { - CrxTile *tile = img->tiles + tRow * img->tileRows + tCol; - CrxPlaneComp *planeComp = tile->comps + planeNumber; - uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset; - - // decode single tile - if (crxSetupSubbandData(img, planeComp, tile, tileMdatOffset)) - return -1; - - if (img->levels) - { - if (crxIdwt53FilterInitialize(planeComp, img->levels - 1)) - return -1; - for (int i = 0; i < tile->height; ++i) - { - if (crxIdwt53FilterDecode(planeComp, img->levels - 1) || - crxIdwt53FilterTransform(planeComp, img->levels - 1)) - return -1; - int32_t *lineData = - crxIdwt53FilterGetLine(planeComp, img->levels - 1); - crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, - lineData, tile->width); - } - } - else - { - // we have the only subband in this case - if (!planeComp->subBands->dataSize) - { - memset(planeComp->subBands->bandBuf, 0, - planeComp->subBands->bandSize); - return 0; - } - - for (int i = 0; i < tile->height; ++i) - { - if (crxDecodeLine(planeComp->subBands->bandParam, - planeComp->subBands->bandBuf)) - return -1; - int32_t *lineData = (int32_t *)planeComp->subBands->bandBuf; - crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, - lineData, tile->width); - } - } - imageCol += tile->width; - } - imageRow += img->tiles[tRow * img->tileRows].height; - } - - return 0; -} - - -namespace { - -typedef DCraw::CanonCR3Data::crx_data_header_t crx_data_header_t; - - -int crxReadSubbandHeaders(crx_data_header_t *hdr, CrxImage *img, CrxTile *tile, - CrxPlaneComp *comp, uint8_t **subbandMdatPtr, - uint32_t *mdatSize) -{ - CrxSubband *band = comp->subBands + img->subbandCount - 1; // set to last band - uint32_t bandHeight = tile->height; - uint32_t bandWidth = tile->width; - int32_t bandWidthExCoef = 0; - int32_t bandHeightExCoef = 0; - if (img->levels) - { - // Build up subband sequences to crxDecode to a level in a header - - // Coefficient structure is a bit unclear and convoluted: - // 3 levels max - 8 groups (for tile width rounded to 8 bytes) - // of 3 band per level 4 sets of coefficients for each - int32_t *rowExCoef = - exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7); - int32_t *colExCoef = - exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7); - for (int level = 0; level < img->levels; ++level) - { - int32_t widthOddPixel = bandWidth & 1; - int32_t heightOddPixel = bandHeight & 1; - bandWidth = (widthOddPixel + bandWidth) >> 1; - bandHeight = (heightOddPixel + bandHeight) >> 1; - - int32_t bandWidthExCoef0 = 0; - int32_t bandWidthExCoef1 = 0; - int32_t bandHeightExCoef0 = 0; - int32_t bandHeightExCoef1 = 0; - if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - bandWidthExCoef0 = rowExCoef[0]; - bandWidthExCoef1 = rowExCoef[1]; - } - if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT) - ++bandWidthExCoef0; - if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) - { - bandHeightExCoef0 = colExCoef[0]; - bandHeightExCoef1 = colExCoef[1]; - } - if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP) - ++bandHeightExCoef0; - - band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel; - band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel; - - band[-1].width = bandWidth + bandWidthExCoef1; - band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel; - - band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel; - band[-2].height = bandHeight + bandHeightExCoef1; - - rowExCoef += 4; - colExCoef += 4; - band -= 3; - } - bandWidthExCoef = bandHeightExCoef = 0; - if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - bandWidthExCoef = - exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) + - 4 * (img->levels - 1) + 1]; - if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) - bandHeightExCoef = - exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) + - 4 * (img->levels - 1) + 1]; - } - band->width = bandWidthExCoef + bandWidth; - band->height = bandHeightExCoef + bandHeight; - - if (!img->subbandCount) - return 0; - int32_t curSubband = 0; - int32_t subbandOffset = 0; - band = comp->subBands; - for (int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++) - { - if (*mdatSize < 0xC) - return -1; - - if (sgetn(2, *subbandMdatPtr) != 0xFF03) - return -1; - - uint32_t bitData = sgetn(4, *subbandMdatPtr + 8); - uint32_t subbandSize = sgetn(4, *subbandMdatPtr + 4); - - if (curSubband != bitData >> 28) - { - band->dataSize = subbandSize; - return -1; - } - band->dataSize = subbandSize - (bitData & 0x7FF); - band->supportsPartial = bitData & 0x8000 ? 1 : 0; - band->dataOffset = subbandOffset; - band->quantValue = (bitData >> 19) & 0xFF; - band->paramK = 0; - band->bandParam = 0; - band->bandBuf = 0; - band->bandSize = 0; - - subbandOffset += subbandSize; - - *subbandMdatPtr += 0xC; - *mdatSize -= 0xC; - } - return 0; -} - -int crxReadImageHeaders(crx_data_header_t *hdr, CrxImage *img, uint8_t *mdatPtr, - uint32_t mdatSize) -{ - int nTiles = img->tileRows * img->tileCols; - - if (!nTiles) - return -1; - - if (!img->tiles) - { - img->tiles = (CrxTile *)malloc( - sizeof(CrxTile) * nTiles + - sizeof(CrxPlaneComp) * nTiles * img->nPlanes + - sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount); - if (!img->tiles) - return -1; - - // memory areas in allocated chunk - CrxTile *tile = img->tiles; - CrxPlaneComp *comps = (CrxPlaneComp *)(tile + nTiles); - CrxSubband *bands = (CrxSubband *)(comps + img->nPlanes * nTiles); - - for (int curTile = 0; curTile < nTiles; curTile++, tile++) - { - tile->tileFlag = 0; // tile neighbouring flags - tile->tileNumber = curTile; - tile->tileSize = 0; - tile->comps = comps + curTile * img->nPlanes; - - if ((curTile + 1) % img->tileCols) - { - // not the last tile in a tile row - tile->width = hdr->tileWidth; - if (img->tileCols > 1) - { - tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT; - if (curTile % img->tileCols) - // not the first tile in tile row - tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT; - } - } - else - { - // last tile in a tile row - tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1); - if (img->tileCols > 1) - tile->tileFlag = E_HAS_TILES_ON_THE_LEFT; - } - if (curTile < nTiles - img->tileCols) - { - // in first tile row - tile->height = hdr->tileHeight; - if (img->tileRows > 1) - { - tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM; - if (curTile >= img->tileCols) - tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; - } - } - else - { - // non first tile row - tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1); - if (img->tileRows > 1) - tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; - } - if (img->nPlanes) - { - CrxPlaneComp *comp = tile->comps; - CrxSubband *band = bands + curTile * img->nPlanes * img->subbandCount; - - for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++) - { - comp->compNumber = curComp; - comp->supportsPartial = 1; - comp->tileFlag = tile->tileFlag; - comp->subBands = band; - comp->compBuf = 0; - comp->waveletTransform = 0; - if (img->subbandCount) - { - for (int curBand = 0; curBand < img->subbandCount; - curBand++, band++) - { - band->supportsPartial = 0; - band->quantValue = 4; - band->bandParam = 0; - band->dataSize = 0; + std::int32_t* lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + + if (wavelet->height > 1) { + if ( + !crxDecodeLineWithIQuantization(comp->subBands + curBand + 1) + || !crxDecodeLineWithIQuantization(comp->subBands + curBand + 2) + || !crxDecodeLineWithIQuantization(comp->subBands + curBand + 3) + ) { + return false; } - } + + std::int32_t* const lineBufL0 = wavelet->lineBuf[0]; + const std::int32_t* const lineBufL1 = wavelet->lineBuf[1]; + std::int32_t* lineBufL2 = wavelet->lineBuf[2]; + + if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP) { + crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet, comp->tileFlag); + + if (!crxDecodeLineWithIQuantization(comp->subBands + curBand + 3)|| !crxDecodeLineWithIQuantization(comp->subBands + curBand + 2)) { + return false; + } + + const std::int32_t* band2Buf = wavelet->subband2Buf; + const std::int32_t* band3Buf = wavelet->subband3Buf; + + // process L band + if (wavelet->width <= 1) { + lineBufL2[0] = band2Buf[0]; + } else { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band3Buf; + } else { + lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + lineBufL2[2] = delta; + + ++band2Buf; + ++band3Buf; + lineBufL2 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + + if (wavelet->width & 1) { + lineBufL2[2] = delta; + } + } else if (wavelet->width & 1) { + const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + lineBufL2[2] = delta; + } else { + lineBufL2[1] = band3Buf[0] + lineBufL2[0]; + } + } + + // process H band + for (std::int32_t i = 0; i < wavelet->width; ++i) { + lineBufH0[i] = lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2); + } + } else { + crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet, comp->tileFlag); + + for (int i = 0; i < wavelet->width; ++i) { + lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1); + } + } + + if (!crxIdwt53FilterDecode(comp, curLevel) || !crxIdwt53FilterTransform(comp, curLevel)) { + return false; + } + } else { + if (!crxDecodeLineWithIQuantization(comp->subBands + curBand + 1)) { + return false; + } + + const std::int32_t* band0Buf = wavelet->subband0Buf; + const std::int32_t* band1Buf = wavelet->subband1Buf; + + // process H band + if (wavelet->width <= 1) { + lineBufH0[0] = band0Buf[0]; + } else { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + ++band1Buf; + } else { + lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + } + + ++band0Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + + ++band0Buf; + ++band1Buf; + lineBufH0 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + } else if (wavelet->width & 1) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + } else { + lineBufH0[1] = band1Buf[0] + lineBufH0[0]; + } + } + + ++wavelet->curLine; + ++wavelet->curH; + wavelet->fltTapH = (wavelet->fltTapH + 1) % 5; } - } } - } - uint32_t tileOffset = 0; - uint32_t dataSize = mdatSize; - uint8_t *dataPtr = mdatPtr; - CrxTile *tile = img->tiles; - - for (int curTile = 0; curTile < nTiles; curTile++, tile++) - { - if (dataSize < 0xC) - return -1; - - if (sgetn(2, dataPtr) != 0xFF01) - return -1; - if (sgetn(2, dataPtr + 8) != curTile) - return -1; - - dataSize -= 0xC; - - tile->tileSize = sgetn(4, dataPtr + 4); - tile->dataOffset = tileOffset; - - int32_t hdrExtraBytes = sgetn(2, dataPtr + 2) - 8; - tileOffset += tile->tileSize; - dataPtr += hdrExtraBytes + 0xC; - dataSize -= hdrExtraBytes; - - uint32_t compOffset = 0; - CrxPlaneComp *comp = tile->comps; - - for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++) - { - if (dataSize < 0xC) - return -1; - - if (sgetn(2, dataPtr) != 0xFF02) - return -1; - if (compNum != dataPtr[8] >> 4) - return -1; - - comp->compSize = sgetn(4, dataPtr + 4); - - int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3; - comp->supportsPartial = (dataPtr[8] & 8) != 0; - - comp->dataOffset = compOffset; - comp->tileFlag = tile->tileFlag; - - compOffset += comp->compSize; - dataSize -= 0xC; - dataPtr += 0xC; - - comp->roundedBitsMask = 0; - - if (compHdrRoundedBits) - { - if (img->levels || !comp->supportsPartial) - return -1; - - comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1); - } - - if (crxReadSubbandHeaders(hdr, img, tile, comp, &dataPtr, &dataSize)) - return -1; - } - } - return 0; + return true; } -int crxSetupImageData(crx_data_header_t *hdr, CrxImage *img, int16_t *outBuf, - uint64_t mdatOffset, uint32_t mdatSize, - uint8_t *mdatHdrPtr) +void crxFreeSubbandData(CrxImage* image, CrxPlaneComp* comp) { - int IncrBitTable[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0}; - - img->planeWidth = hdr->f_width; - img->planeHeight = hdr->f_height; - - if (hdr->tileWidth < 0x16 || hdr->tileHeight < 0x16 || - img->planeWidth > 0x7FFF || img->planeHeight > 0x7FFF) - return -1; - - img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth; - img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight; - - if (img->tileCols > 0xFF || img->tileRows > 0xFF || - img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 || - img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16) - return -1; - - img->tiles = 0; - img->levels = hdr->imageLevels; - img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL - img->nPlanes = hdr->nPlanes; - img->nBits = hdr->nBits; - img->encType = hdr->encType; - img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1; - img->mdatOffset = mdatOffset + hdr->mdatHdrSize; - img->mdatSize = mdatSize; - img->planeBuf = 0; - img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = 0; - - // The encoding type 3 needs all 4 planes to be decoded to generate row of - // RGGB values. It seems to be using some other colour space for raw encoding - // It is a massive buffer so ideallly it will need a different approach: - // decode planes line by line and convert single line then without - // intermediate plane buffer. At the moment though it's too many changes so - // left as is. - if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8) - { - img->planeBuf = - (int16_t *)malloc(img->planeHeight * img->planeWidth * img->nPlanes * - ((img->samplePrecision + 7) >> 3)); - if (!img->planeBuf) - return -1; - } - - int32_t rowSize = 2 * img->planeWidth; - - if (img->nPlanes == 1) - img->outBufs[0] = outBuf; - else - switch (hdr->cfaLayout) - { - case 0: - // R G - // G B - img->outBufs[0] = outBuf; - img->outBufs[1] = outBuf + 1; - img->outBufs[2] = outBuf + rowSize; - img->outBufs[3] = img->outBufs[2] + 1; - break; - case 1: - // G R - // B G - img->outBufs[1] = outBuf; - img->outBufs[0] = outBuf + 1; - img->outBufs[3] = outBuf + rowSize; - img->outBufs[2] = img->outBufs[3] + 1; - break; - case 2: - // G B - // R G - img->outBufs[2] = outBuf; - img->outBufs[3] = outBuf + 1; - img->outBufs[0] = outBuf + rowSize; - img->outBufs[1] = img->outBufs[0] + 1; - break; - case 3: - // B G - // G R - img->outBufs[3] = outBuf; - img->outBufs[2] = outBuf + 1; - img->outBufs[1] = outBuf + rowSize; - img->outBufs[0] = img->outBufs[1] + 1; - break; + if (comp->compBuf) { + free(comp->compBuf); + comp->compBuf = nullptr; } - // read header - return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize); + if (!comp->subBands) { + return; + } + + for (std::int32_t i = 0; i < image->subbandCount; ++i) { + if (comp->subBands[i].bandParam) { + free(comp->subBands[i].bandParam); + comp->subBands[i].bandParam = nullptr; + } + + comp->subBands[i].bandBuf = nullptr; + comp->subBands[i].bandSize = 0; + } } -int crxFreeImageData(CrxImage *img) +void crxConvertPlaneLine( + CrxImage* img, + int imageRow, + int imageCol = 0, + int plane = 0, + const std::int32_t* lineData = nullptr, + int lineLength = 0 +) { - CrxTile *tile = img->tiles; - int nTiles = img->tileRows * img->tileCols; + if (lineData) { + std::uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol; - if (img->tiles) - { - for (int32_t curTile = 0; curTile < nTiles; curTile++, tile++) - if (tile[curTile].comps) - for (int32_t curPlane = 0; curPlane < img->nPlanes; curPlane++) - crxFreeSubbandData(img, tile[curTile].comps + curPlane); - free(img->tiles); - img->tiles = 0; - } + if (img->encType == 1) { + const std::int32_t maxVal = 1 << (img->nBits - 1); + const std::int32_t minVal = -maxVal; - if (img->planeBuf) - { - free(img->planeBuf); - img->planeBuf = 0; - } + for (int i = 0; i < lineLength; ++i) { + img->outBufs[plane][rawOffset + 2 * i] = rtengine::LIM(lineData[i], minVal, maxVal - 1); + } + } else if (img->encType == 3) { + // copy to intermediate planeBuf + rawOffset = plane * img->planeWidth * img->planeHeight + img->planeWidth * imageRow + imageCol; - return 0; + for (int i = 0; i < lineLength; ++i) { + img->planeBuf[rawOffset + i] = lineData[i]; + } + } else if (img->nPlanes == 4) { + const std::int32_t median = 1 << (img->nBits - 1); + const std::int32_t maxVal = (1 << img->nBits) - 1; + + for (int i = 0; i < lineLength; ++i) { + img->outBufs[plane][rawOffset + 2 * i] = rtengine::LIM(median + lineData[i], 0, maxVal); + } + } else if (img->nPlanes == 1) { + const std::int32_t maxVal = (1 << img->nBits) - 1; + const std::int32_t median = 1 << (img->nBits - 1); + + rawOffset = img->planeWidth * imageRow + imageCol; + + for (int i = 0; i < lineLength; ++i) { + img->outBufs[0][rawOffset + i] = rtengine::LIM(median + lineData[i], 0, maxVal); + } + } + } else if (img->encType == 3 && img->planeBuf) { + const std::int32_t planeSize = img->planeWidth * img->planeHeight; + const std::int16_t* const plane0 = img->planeBuf + imageRow * img->planeWidth; + const std::int16_t* const plane1 = plane0 + planeSize; + const std::int16_t* const plane2 = plane1 + planeSize; + const std::int16_t* const plane3 = plane2 + planeSize; + + const std::int32_t median = 1 << (img->nBits - 1) << 10; + const std::int32_t maxVal = (1 << img->nBits) - 1; + const std::uint32_t rawLineOffset = 4 * img->planeWidth * imageRow; + + // for this stage - all except imageRow is ignored + for (int i = 0; i < img->planeWidth; ++i) { + std::int32_t gr = median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i]; + + if (gr < 0) { + gr = -(((std::abs(gr) + 512) >> 9) & ~1); + } else { + gr = ((std::abs(gr) + 512) >> 9) & ~1; + } + + // Essentially R = round(median + P0 + 1.474*P3) + std::int32_t val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10; + img->outBufs[0][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal); + // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3) + val = (plane2[i] + gr + 1) >> 1; + img->outBufs[1][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal); + // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3) + val = (gr - plane2[i] + 1) >> 1; + img->outBufs[2][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal); + // Essentially B = round(median + P0 + 1.881*P1) + val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10; + img->outBufs[3][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal); + } + } +} + +bool crxParamInit( + CrxBandParam** param, + std::uint64_t subbandMdatOffset, + std::uint64_t subbandDataSize, + std::uint32_t subbandWidth, + std::uint32_t subbandHeight, + bool supportsPartial, + std::uint32_t roundedBitsMask, + LibRaw_abstract_datastream* input +) +{ + const std::int32_t progrDataSize = + supportsPartial + ? 0 + : sizeof(std::int32_t) * subbandWidth; + const std::int32_t paramLength = 2 * subbandWidth + 4; + + std::uint8_t* paramBuf = static_cast(calloc(1, sizeof(CrxBandParam) + sizeof(std::int32_t) * paramLength + progrDataSize)); + + if (!paramBuf) { + return false; + } + + *param = reinterpret_cast(paramBuf); + + paramBuf += sizeof(CrxBandParam); + + (*param)->paramData = reinterpret_cast(paramBuf); + (*param)->nonProgrData = + progrDataSize + ? (*param)->paramData + paramLength + : nullptr; + (*param)->subbandWidth = subbandWidth; + (*param)->subbandHeight = subbandHeight; + (*param)->roundedBits = 0; + (*param)->curLine = 0; + (*param)->roundedBitsMask = roundedBitsMask; + (*param)->supportsPartial = supportsPartial; + (*param)->bitStream.bitData = 0; + (*param)->bitStream.bitsLeft = 0; + (*param)->bitStream.mdatSize = subbandDataSize; + (*param)->bitStream.curPos = 0; + (*param)->bitStream.curBufSize = 0; + (*param)->bitStream.curBufOffset = subbandMdatOffset; + (*param)->bitStream.input = input; + + crxFillBuffer(&(*param)->bitStream); + + return true; +} + +bool crxSetupSubbandData( + CrxImage* img, + CrxPlaneComp* planeComp, + const CrxTile* tile, + std::uint32_t mdatOffset +) +{ + long compDataSize = 0; + long waveletDataOffset = 0; + long compCoeffDataOffset = 0; + const std::int32_t toSubbands = 3 * img->levels + 1; + + CrxSubband* const subbands = planeComp->subBands; + + // calculate sizes + for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) { + subbands[subbandNum].bandSize = subbands[subbandNum].width * sizeof(std::int32_t); // 4 bytes + compDataSize += subbands[subbandNum].bandSize; + } + + if (img->levels) { + const std::int32_t encLevels = + img->levels + ? img->levels + : 1; + waveletDataOffset = (compDataSize + 7) & ~7; + compDataSize = (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7; + compCoeffDataOffset = compDataSize; + + // calc wavelet line buffer sizes (always at one level up from current) + for (int level = 0; level < img->levels; ++level) { + if (level < img->levels - 1) { + compDataSize += 8 * sizeof(std::int32_t) * planeComp->subBands[3 * (level + 1) + 2].width; + } else { + compDataSize += 8 * sizeof(std::int32_t) * tile->width; + } + } + } + + // buffer allocation + planeComp->compBuf = static_cast(malloc(compDataSize)); + + if (!planeComp->compBuf) { + return false; + } + + // subbands buffer and sizes initialisation + const std::uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset; + std::uint8_t* subbandBuf = planeComp->compBuf; + + for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) { + subbands[subbandNum].bandBuf = subbandBuf; + subbandBuf += subbands[subbandNum].bandSize; + subbands[subbandNum].mdatOffset = subbandMdatOffset + subbands[subbandNum].dataOffset; + } + + // wavelet data initialisation + if (img->levels) { + CrxWaveletTransform* const waveletTransforms = reinterpret_cast(planeComp->compBuf + waveletDataOffset); + std::int32_t* paramData = reinterpret_cast(planeComp->compBuf + compCoeffDataOffset); + + planeComp->waveletTransform = waveletTransforms; + waveletTransforms[0].subband0Buf = reinterpret_cast(subbands->bandBuf); + + for (int level = 0; level < img->levels; ++level) { + const std::int32_t band = 3 * level + 1; + + std::int32_t transformWidth = 0; + + if (level >= img->levels - 1) { + waveletTransforms[level].height = tile->height; + transformWidth = tile->width; + } else { + waveletTransforms[level].height = subbands[band + 3].height; + transformWidth = subbands[band + 4].width; + } + + waveletTransforms[level].width = transformWidth; + waveletTransforms[level].lineBuf[0] = paramData; + waveletTransforms[level].lineBuf[1] = waveletTransforms[level].lineBuf[0] + transformWidth; + waveletTransforms[level].lineBuf[2] = waveletTransforms[level].lineBuf[1] + transformWidth; + waveletTransforms[level].lineBuf[3] = waveletTransforms[level].lineBuf[2] + transformWidth; + waveletTransforms[level].lineBuf[4] = waveletTransforms[level].lineBuf[3] + transformWidth; + waveletTransforms[level].lineBuf[5] = waveletTransforms[level].lineBuf[4] + transformWidth; + waveletTransforms[level].lineBuf[6] = waveletTransforms[level].lineBuf[5] + transformWidth; + waveletTransforms[level].lineBuf[7] = waveletTransforms[level].lineBuf[6] + transformWidth; + waveletTransforms[level].curLine = 0; + waveletTransforms[level].curH = 0; + waveletTransforms[level].fltTapH = 0; + waveletTransforms[level].subband1Buf = reinterpret_cast(subbands[band].bandBuf); + waveletTransforms[level].subband2Buf = reinterpret_cast(subbands[band + 1].bandBuf); + waveletTransforms[level].subband3Buf = reinterpret_cast(subbands[band + 2].bandBuf); + + paramData = waveletTransforms[level].lineBuf[7] + transformWidth; + } + } + + // decoding params and bitstream initialisation + for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) { + if (subbands[subbandNum].dataSize) { + bool supportsPartial = false; + std::uint32_t roundedBitsMask = 0; + + if (planeComp->supportsPartial && subbandNum == 0) { + roundedBitsMask = planeComp->roundedBitsMask; + supportsPartial = true; + } + + if ( + !crxParamInit( + &subbands[subbandNum].bandParam, + subbands[subbandNum].mdatOffset, + subbands[subbandNum].dataSize, + subbands[subbandNum].width, + subbands[subbandNum].height, + supportsPartial, + roundedBitsMask, + img->input + ) + ) { + return false; + } + } + } + + return true; } } // namespace -void DCraw::crxLoadDecodeLoop(void *img, int nPlanes) +bool DCraw::crxDecodePlane(void* p, std::uint32_t planeNumber) +{ + CrxImage* const img = static_cast(p); + int imageRow = 0; + + for (int tRow = 0; tRow < img->tileRows; ++tRow) { + int imageCol = 0; + + for (int tCol = 0; tCol < img->tileCols; ++tCol) { + const CrxTile* const tile = img->tiles + tRow * img->tileRows + tCol; + CrxPlaneComp* const planeComp = tile->comps + planeNumber; + const std::uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset; + + // decode single tile + if (!crxSetupSubbandData(img, planeComp, tile, tileMdatOffset)) { + return false; + } + + if (img->levels) { + if (!crxIdwt53FilterInitialize(planeComp, img->levels - 1)) { + return false; + } + + for (int i = 0; i < tile->height; ++i) { + if (!crxIdwt53FilterDecode(planeComp, img->levels - 1) || !crxIdwt53FilterTransform(planeComp, img->levels - 1)) { + return false; + } + + const std::int32_t* const lineData = crxIdwt53FilterGetLine(planeComp, img->levels - 1); + crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, lineData, tile->width); + } + } else { + // we have the only subband in this case + if (!planeComp->subBands->dataSize) { + memset(planeComp->subBands->bandBuf, 0, planeComp->subBands->bandSize); + return true; + } + + for (int i = 0; i < tile->height; ++i) { + if (!crxDecodeLine(planeComp->subBands->bandParam, planeComp->subBands->bandBuf)) { + return false; + } + + const std::int32_t* const lineData = reinterpret_cast(planeComp->subBands->bandBuf); + crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, lineData, tile->width); + } + } + + imageCol += tile->width; + } + + imageRow += img->tiles[tRow * img->tileRows].height; + } + + return true; +} + +namespace +{ + +using crx_data_header_t = DCraw::CanonCR3Data::crx_data_header_t; + +bool crxReadSubbandHeaders( + CrxImage* img, + CrxTile* tile, + CrxPlaneComp* comp, + std::uint8_t** subbandMdatPtr, + std::uint32_t* mdatSize +) +{ + CrxSubband* band = comp->subBands + img->subbandCount - 1; // set to last band + std::uint32_t bandHeight = tile->height; + std::uint32_t bandWidth = tile->width; + std::int32_t bandWidthExCoef = 0; + std::int32_t bandHeightExCoef = 0; + + if (img->levels) { + // Build up subband sequences to crxDecode to a level in a header + + // Coefficient structure is a bit unclear and convoluted: + // 3 levels max - 8 groups (for tile width rounded to 8 bytes) + // of 3 band per level 4 sets of coefficients for each + const std::int32_t* rowExCoef = exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7); + const std::int32_t* colExCoef = exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7); + + for (int level = 0; level < img->levels; ++level) { + const std::int32_t widthOddPixel = bandWidth & 1; + const std::int32_t heightOddPixel = bandHeight & 1; + bandWidth = (widthOddPixel + bandWidth) >> 1; + bandHeight = (heightOddPixel + bandHeight) >> 1; + + std::int32_t bandWidthExCoef0 = 0; + std::int32_t bandWidthExCoef1 = 0; + std::int32_t bandHeightExCoef0 = 0; + std::int32_t bandHeightExCoef1 = 0; + + if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + bandWidthExCoef0 = rowExCoef[0]; + bandWidthExCoef1 = rowExCoef[1]; + } + + if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + ++bandWidthExCoef0; + } + + if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) { + bandHeightExCoef0 = colExCoef[0]; + bandHeightExCoef1 = colExCoef[1]; + } + + if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP) { + ++bandHeightExCoef0; + } + + band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel; + band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel; + + band[-1].width = bandWidth + bandWidthExCoef1; + band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel; + + band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel; + band[-2].height = bandHeight + bandHeightExCoef1; + + rowExCoef += 4; + colExCoef += 4; + band -= 3; + } + + bandWidthExCoef = 0; + bandHeightExCoef = 0; + + if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + bandWidthExCoef = exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) + 4 * (img->levels - 1) + 1]; + } + + if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) { + bandHeightExCoef = exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) + 4 * (img->levels - 1) + 1]; + } + } + + band->width = bandWidthExCoef + bandWidth; + band->height = bandHeightExCoef + bandHeight; + + if (!img->subbandCount) { + return true; + } + + std::int32_t subbandOffset = 0; + band = comp->subBands; + + for (unsigned int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++) { + if (*mdatSize < 0xC) { + return false; + } + + if (sgetn(2, *subbandMdatPtr) != 0xFF03) { + return false; + } + + const std::uint32_t bitData = sgetn(4, *subbandMdatPtr + 8); + const std::uint32_t subbandSize = sgetn(4, *subbandMdatPtr + 4); + + if (curSubband != bitData >> 28) { + band->dataSize = subbandSize; + return false; + } + + band->dataSize = subbandSize - (bitData & 0x7FF); + band->supportsPartial = bitData & 0x8000; + band->dataOffset = subbandOffset; + band->quantValue = (bitData >> 19) & 0xFF; + band->paramK = 0; + band->bandParam = nullptr; + band->bandBuf = nullptr; + band->bandSize = 0; + + subbandOffset += subbandSize; + + *subbandMdatPtr += 0xC; + *mdatSize -= 0xC; + } + + return true; +} + +bool crxReadImageHeaders( + crx_data_header_t* hdr, + CrxImage* img, + std::uint8_t* mdatPtr, + std::uint32_t mdatSize +) +{ + const unsigned int nTiles = img->tileRows * img->tileCols; + + if (!nTiles) { + return false; + } + + if (!img->tiles) { + img->tiles = static_cast( + malloc( + sizeof(CrxTile) * nTiles + + sizeof(CrxPlaneComp) * nTiles * img->nPlanes + + sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount + ) + ); + + if (!img->tiles) { + return false; + } + + // memory areas in allocated chunk + CrxTile* tile = img->tiles; + CrxPlaneComp* const comps = reinterpret_cast(tile + nTiles); + CrxSubband* const bands = reinterpret_cast(comps + img->nPlanes * nTiles); + + for (unsigned int curTile = 0; curTile < nTiles; curTile++, tile++) { + tile->tileFlag = 0; // tile neighbouring flags + tile->tileNumber = curTile; + tile->tileSize = 0; + tile->comps = comps + curTile * img->nPlanes; + + if ((curTile + 1) % img->tileCols) { + // not the last tile in a tile row + tile->width = hdr->tileWidth; + + if (img->tileCols > 1) { + tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT; + + if (curTile % img->tileCols) { + // not the first tile in tile row + tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT; + } + } + } else { + // last tile in a tile row + tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1); + + if (img->tileCols > 1) { + tile->tileFlag = E_HAS_TILES_ON_THE_LEFT; + } + } + + if (curTile < nTiles - img->tileCols) { + // in first tile row + tile->height = hdr->tileHeight; + + if (img->tileRows > 1) { + tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM; + + if (curTile >= img->tileCols) { + tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; + } + } + } else { + // non first tile row + tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1); + + if (img->tileRows > 1) { + tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; + } + } + + if (img->nPlanes) { + CrxPlaneComp* comp = tile->comps; + CrxSubband* band = bands + curTile * img->nPlanes * img->subbandCount; + + for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++) { + comp->compNumber = curComp; + comp->supportsPartial = true; + comp->tileFlag = tile->tileFlag; + comp->subBands = band; + comp->compBuf = nullptr; + comp->waveletTransform = nullptr; + + if (img->subbandCount) { + for (int curBand = 0; curBand < img->subbandCount; curBand++, band++) { + band->supportsPartial = false; + band->quantValue = 4; + band->bandParam = nullptr; + band->dataSize = 0; + } + } + } + } + } + } + + std::uint32_t tileOffset = 0; + std::uint32_t dataSize = mdatSize; + std::uint8_t* dataPtr = mdatPtr; + CrxTile* tile = img->tiles; + + for (unsigned int curTile = 0; curTile < nTiles; curTile++, tile++) { + if (dataSize < 0xC) { + return false; + } + + if (sgetn(2, dataPtr) != 0xFF01) { + return false; + } + + if (sgetn(2, dataPtr + 8) != curTile) { + return false; + } + + dataSize -= 0xC; + + tile->tileSize = sgetn(4, dataPtr + 4); + tile->dataOffset = tileOffset; + + const std::int32_t hdrExtraBytes = sgetn(2, dataPtr + 2) - 8; + tileOffset += tile->tileSize; + dataPtr += hdrExtraBytes + 0xC; + dataSize -= hdrExtraBytes; + + std::uint32_t compOffset = 0; + CrxPlaneComp* comp = tile->comps; + + for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++) { + if (dataSize < 0xC) { + return false; + } + + if (sgetn(2, dataPtr) != 0xFF02) { + return false; + } + + if (compNum != dataPtr[8] >> 4) { + return false; + } + + comp->compSize = sgetn(4, dataPtr + 4); + + std::int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3; + comp->supportsPartial = (dataPtr[8] & 8) != 0; + + comp->dataOffset = compOffset; + comp->tileFlag = tile->tileFlag; + + compOffset += comp->compSize; + dataSize -= 0xC; + dataPtr += 0xC; + + comp->roundedBitsMask = 0; + + if (compHdrRoundedBits) { + if (img->levels || !comp->supportsPartial) { + return false; + } + + comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1); + } + + if (!crxReadSubbandHeaders(img, tile, comp, &dataPtr, &dataSize)) { + return false; + } + } + } + + return true; +} + +bool crxSetupImageData( + crx_data_header_t* hdr, + CrxImage* img, + std::int16_t* outBuf, + std::uint64_t mdatOffset, + std::uint32_t mdatSize, + std::uint8_t* mdatHdrPtr +) +{ + constexpr bool IncrBitTable[32] = { + false, false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, + false, false, true, false, false, true, true, true, false, true, true, true, false, false, false, false + }; + + img->planeWidth = hdr->f_width; + img->planeHeight = hdr->f_height; + + if ( + hdr->tileWidth < 0x16 + || hdr->tileHeight < 0x16 + || img->planeWidth > 0x7FFF + || img->planeHeight > 0x7FFF + ) { + return false; + } + + img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth; + img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight; + + if (img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 || img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16) { + return false; + } + + img->tiles = nullptr; + img->levels = hdr->imageLevels; + img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL + img->nPlanes = hdr->nPlanes; + img->nBits = hdr->nBits; + img->encType = hdr->encType; + img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1; + img->mdatOffset = mdatOffset + hdr->mdatHdrSize; + img->mdatSize = mdatSize; + img->planeBuf = nullptr; + img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = nullptr; + + // The encoding type 3 needs all 4 planes to be decoded to generate row of + // RGGB values. It seems to be using some other colour space for raw encoding + // It is a massive buffer so ideallly it will need a different approach: + // decode planes line by line and convert single line then without + // intermediate plane buffer. At the moment though it's too many changes so + // left as is. + if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8) { + img->planeBuf = static_cast( + malloc(img->planeHeight * img->planeWidth * img->nPlanes * ((img->samplePrecision + 7) >> 3)) + ); + + if (!img->planeBuf) { + return false; + } + } + + const std::int32_t rowSize = 2 * img->planeWidth; + + if (img->nPlanes == 1) { + img->outBufs[0] = outBuf; + } else { + switch (hdr->cfaLayout) { + case 0: { + // R G + // G B + img->outBufs[0] = outBuf; + img->outBufs[1] = outBuf + 1; + img->outBufs[2] = outBuf + rowSize; + img->outBufs[3] = img->outBufs[2] + 1; + break; + } + + case 1: { + // G R + // B G + img->outBufs[1] = outBuf; + img->outBufs[0] = outBuf + 1; + img->outBufs[3] = outBuf + rowSize; + img->outBufs[2] = img->outBufs[3] + 1; + break; + } + + case 2: { + // G B + // R G + img->outBufs[2] = outBuf; + img->outBufs[3] = outBuf + 1; + img->outBufs[0] = outBuf + rowSize; + img->outBufs[1] = img->outBufs[0] + 1; + break; + } + + case 3: { + // B G + // G R + img->outBufs[3] = outBuf; + img->outBufs[2] = outBuf + 1; + img->outBufs[1] = outBuf + rowSize; + img->outBufs[0] = img->outBufs[1] + 1; + break; + } + } + } + + // read header + return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize); +} + +void crxFreeImageData(CrxImage* img) +{ + CrxTile* tile = img->tiles; + const int nTiles = img->tileRows * img->tileCols; + + if (img->tiles) { + for (std::int32_t curTile = 0; curTile < nTiles; curTile++, tile++) { + if (tile[curTile].comps) { + for (std::int32_t curPlane = 0; curPlane < img->nPlanes; ++curPlane) { + crxFreeSubbandData(img, tile[curTile].comps + curPlane); + } + } + } + + free(img->tiles); + img->tiles = nullptr; + } + + if (img->planeBuf) { + free(img->planeBuf); + img->planeBuf = nullptr; + } +} + +} // namespace + +void DCraw::crxLoadDecodeLoop(void* img, int nPlanes) { #ifdef _OPENMP - int results[4]; // nPlanes is always <= 4 -#pragma omp parallel for - for (int32_t plane = 0; plane < nPlanes; ++plane) - results[plane] = crxDecodePlane(img, plane); + bool results[4]; // nPlanes is always <= 4 + #pragma omp parallel for + + for (std::int32_t plane = 0; plane < nPlanes; ++plane) { + results[plane] = crxDecodePlane(img, plane); + } + + for (std::int32_t plane = 0; plane < nPlanes; ++plane) { + if (!results[plane]) { + derror(); + } + } - for (int32_t plane = 0; plane < nPlanes; ++plane) - if (results[plane]) - derror(); #else - for (int32_t plane = 0; plane < nPlanes; ++plane) - if (crxDecodePlane(img, plane)) - derror(); + + for (std::int32_t plane = 0; plane < nPlanes; ++plane) { + if (!crxDecodePlane(img, plane)) { + derror(); + } + } + #endif } -void DCraw::crxConvertPlaneLineDf(void *p, int imageRow) +void DCraw::crxConvertPlaneLineDf(void* p, int imageRow) { - crxConvertPlaneLine((CrxImage *)p, imageRow); + crxConvertPlaneLine(static_cast(p), imageRow); } -void DCraw::crxLoadFinalizeLoopE3(void *p, int planeHeight) +void DCraw::crxLoadFinalizeLoopE3(void* p, int planeHeight) { #ifdef _OPENMP -#pragma omp parallel for + #pragma omp parallel for #endif - for (int i = 0; i < planeHeight; ++i) - crxConvertPlaneLineDf(p, i); + + for (int i = 0; i < planeHeight; ++i) { + crxConvertPlaneLineDf(p, i); + } } void DCraw::crxLoadRaw() { - CrxImage img; - if (RT_canon_CR3_data.crx_track_selected < 0 || - RT_canon_CR3_data.crx_track_selected >= - LIBRAW_CRXTRACKS_MAXCOUNT) - derror(); - crx_data_header_t hdr = - RT_canon_CR3_data - .crx_header[RT_canon_CR3_data.crx_track_selected]; + CrxImage img; - LibRaw_abstract_datastream input = { ifp }; - img.input = &input; //libraw_internal_data.internal_data.input; + if (RT_canon_CR3_data.crx_track_selected >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) { + derror(); + } - // update sizes for the planes - if (hdr.nPlanes == 4) - { - hdr.f_width >>= 1; - hdr.f_height >>= 1; - hdr.tileWidth >>= 1; - hdr.tileHeight >>= 1; - } + crx_data_header_t hdr = RT_canon_CR3_data.crx_header[RT_canon_CR3_data.crx_track_selected]; + + LibRaw_abstract_datastream input = {ifp}; + img.input = &input; // libraw_internal_data.internal_data.input; + + // update sizes for the planes + if (hdr.nPlanes == 4) { + hdr.f_width >>= 1; + hdr.f_height >>= 1; + hdr.tileWidth >>= 1; + hdr.tileHeight >>= 1; + } // /*imgdata.color.*/maximum = (1 << hdr.nBits) - 1; - uint8_t *hdrBuf = (uint8_t *)malloc(hdr.mdatHdrSize); + std::uint8_t* const hdrBuf = static_cast(malloc(hdr.mdatHdrSize)); - // read image header + // read image header #ifdef _OPENMP -#pragma omp critical + #pragma omp critical #endif - { + { #ifndef _OPENMP - /*libraw_internal_data.internal_data.input->*/input.lock(); + /*libraw_internal_data.internal_data.input->*/ input.lock(); #endif - /*libraw_internal_data.internal_data.input->*/input.seek( - data_offset, SEEK_SET); - /*libraw_internal_data.internal_data.input->*/input.read(hdrBuf, 1, hdr.mdatHdrSize); + /*libraw_internal_data.internal_data.input->*/ input.seek(data_offset, SEEK_SET); + /*libraw_internal_data.internal_data.input->*/ input.read(hdrBuf, 1, hdr.mdatHdrSize); #ifndef _OPENMP - /*libraw_internal_data.internal_data.input->*/input.unlock(); + /*libraw_internal_data.internal_data.input->*/ input.unlock(); #endif - } + } - // parse and setup the image data - if (crxSetupImageData(&hdr, &img, (int16_t *)raw_image, - hdr.MediaOffset/*data_offset*/, - hdr.MediaSize/*RT_canon_CR3_data.data_size*/, hdrBuf)) - derror(); - free(hdrBuf); + // parse and setup the image data + if (!crxSetupImageData(&hdr, &img, reinterpret_cast(raw_image), hdr.MediaOffset /*data_offset*/, hdr.MediaSize /*RT_canon_CR3_data.data_size*/, hdrBuf)) { + derror(); + } - crxLoadDecodeLoop(&img, hdr.nPlanes); + free(hdrBuf); - if (img.encType == 3) - crxLoadFinalizeLoopE3(&img, img.planeHeight); + crxLoadDecodeLoop(&img, hdr.nPlanes); - crxFreeImageData(&img); + if (img.encType == 3) { + crxLoadFinalizeLoopE3(&img, img.planeHeight); + } + + crxFreeImageData(&img); } -int DCraw::crxParseImageHeader(uchar *cmp1TagData, int nTrack) +bool DCraw::crxParseImageHeader(uchar* cmp1TagData, unsigned int nTrack) { - if (nTrack < 0 || nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT) - return -1; - if (!cmp1TagData) - return -1; + if (nTrack >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) { + return false; + } - crx_data_header_t *hdr = - &RT_canon_CR3_data.crx_header[nTrack]; + if (!cmp1TagData) { + return false; + } - hdr->version = sgetn(2, cmp1TagData + 4); - hdr->f_width = sgetn(4, cmp1TagData + 8); - hdr->f_height = sgetn(4, cmp1TagData + 12); - hdr->tileWidth = sgetn(4, cmp1TagData + 16); - hdr->tileHeight = sgetn(4, cmp1TagData + 20); - hdr->nBits = cmp1TagData[24]; - hdr->nPlanes = cmp1TagData[25] >> 4; - hdr->cfaLayout = cmp1TagData[25] & 0xF; - hdr->encType = cmp1TagData[26] >> 4; - hdr->imageLevels = cmp1TagData[26] & 0xF; - hdr->hasTileCols = cmp1TagData[27] >> 7; - hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1; - hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28); + crx_data_header_t* const hdr = &RT_canon_CR3_data.crx_header[nTrack]; - // validation - if (hdr->version != 0x100 || !hdr->mdatHdrSize) - return -1; - if (hdr->encType == 1) - { - if (hdr->nBits > 15) - return -1; - } - else - { - if (hdr->encType && hdr->encType != 3) - return -1; - if (hdr->nBits > 14) - return -1; - } + hdr->version = sgetn(2, cmp1TagData + 4); + hdr->f_width = sgetn(4, cmp1TagData + 8); + hdr->f_height = sgetn(4, cmp1TagData + 12); + hdr->tileWidth = sgetn(4, cmp1TagData + 16); + hdr->tileHeight = sgetn(4, cmp1TagData + 20); + hdr->nBits = cmp1TagData[24]; + hdr->nPlanes = cmp1TagData[25] >> 4; + hdr->cfaLayout = cmp1TagData[25] & 0xF; + hdr->encType = cmp1TagData[26] >> 4; + hdr->imageLevels = cmp1TagData[26] & 0xF; + hdr->hasTileCols = cmp1TagData[27] >> 7; + hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1; + hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28); - if (hdr->nPlanes == 1) - { - if (hdr->cfaLayout || hdr->encType) - return -1; - if (hdr->nBits != 8) - return -1; - } - else if (hdr->nPlanes != 4 || hdr->f_width & 1 || hdr->f_height & 1 || - hdr->tileWidth & 1 || hdr->tileHeight & 1 || hdr->cfaLayout > 3u || - (hdr->encType && hdr->encType != 1 && hdr->encType != 3) || - hdr->nBits == 8) - return -1; + // validation + if (hdr->version != 0x100 || !hdr->mdatHdrSize) { + return false; + } - if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height) - return -1; + if (hdr->encType == 1) { + if (hdr->nBits > 15) { + return false; + } + } else { + if (hdr->encType && hdr->encType != 3) { + return false; + } - if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1) - return -1; - return 0; + if (hdr->nBits > 14) { + return false; + } + } + + if (hdr->nPlanes == 1) { + if (hdr->cfaLayout || hdr->encType) { + return false; + } + + if (hdr->nBits != 8) { + return false; + } + } else if ( + hdr->nPlanes != 4 + || (hdr->f_width & 1) + || (hdr->f_height & 1) + || (hdr->tileWidth & 1) + || (hdr->tileHeight & 1) + || hdr->cfaLayout > 3 + || ( + hdr->encType + && hdr->encType != 1 + && hdr->encType != 3 + ) + || hdr->nBits == 8 + ) { + return false; + } + + if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height) { + return false; + } + + if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1) { + return false; + } + + return true; } - -#undef _abs -#undef _min -#undef _constrain -#undef libraw_inline -#undef LIBRAW_CRXTRACKS_MAXCOUNT - -#ifdef __GNUC__ // silence warning -#pragma GCC diagnostic pop -#endif diff --git a/rtengine/capturesharpening.cc b/rtengine/capturesharpening.cc index e8770f95a..281a2ad71 100644 --- a/rtengine/capturesharpening.cc +++ b/rtengine/capturesharpening.cc @@ -541,6 +541,7 @@ BENCHFUN double progress = startVal; const double progressStep = (endVal - startVal) * rtengine::SQR(tileSize) / (W * H); + constexpr float minBlend = 0.01f; #ifdef _OPENMP #pragma omp parallel @@ -563,11 +564,17 @@ BENCHFUN if (endOfRow || endOfCol) { // special handling for small tiles at end of row or column if (checkIterStop) { + float maxVal = 0.f; for (int k = 0, ii = endOfCol ? H - fullTileSize + border : i; k < tileSize; ++k, ++ii) { for (int l = 0, jj = endOfRow ? W - fullTileSize + border : j; l < tileSize; ++l, ++jj) { iterCheck[k][l] = oldLuminance[ii][jj] * clipmask[ii][jj] * 0.5f; + maxVal = std::max(maxVal, clipmask[ii][jj]); } } + if (maxVal < minBlend) { + // no pixel of the tile has a blend factor >= minBlend => skip the tile + continue; + } } for (int k = 0, ii = endOfCol ? H - fullTileSize : i - border; k < fullTileSize; ++k, ++ii) { for (int l = 0, jj = endOfRow ? W - fullTileSize : j - border; l < fullTileSize; ++l, ++jj) { @@ -577,11 +584,17 @@ BENCHFUN } } else { if (checkIterStop) { + float maxVal = 0.f; for (int ii = 0; ii < tileSize; ++ii) { for (int jj = 0; jj < tileSize; ++jj) { iterCheck[ii][jj] = oldLuminance[i + ii][j + jj] * clipmask[i + ii][j + jj] * 0.5f; + maxVal = std::max(maxVal, clipmask[i + ii][j + jj]); } } + if (maxVal < minBlend) { + // no pixel of the tile has a blend factor >= minBlend => skip the tile + continue; + } } for (int ii = i; ii < i + fullTileSize; ++ii) { for (int jj = j; jj < j + fullTileSize; ++jj) { @@ -687,6 +700,10 @@ namespace rtengine void RawImageSource::captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) { + if (!(ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS || ri->get_colors() == 1)) { + return; + } + if (plistener) { plistener->setProgressStr(M("TP_PDSHARPENING_LABEL")); plistener->setProgress(0.0); diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 0265219c7..89c1fcaff 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -184,12 +184,12 @@ public: int32_t mdatHdrSize; // Not from header, but from datastream uint32_t MediaSize; - INT64 MediaOffset; + int64_t MediaOffset; uint32_t MediaType; /* 1 -> /C/RAW, 2-> JPEG */ }; static constexpr size_t CRXTRACKS_MAXCOUNT = 16; crx_data_header_t crx_header[CRXTRACKS_MAXCOUNT]; - int crx_track_selected; + unsigned int crx_track_selected; short CR3_CTMDtag; }; protected: @@ -563,16 +563,16 @@ void nikon_14bit_load_raw(); // ported from LibRaw // Canon CR3 support ported from LibRaw //----------------------------------------------------------------------------- void parse_canon_cr3(); -void selectCRXTrack(short maxTrack); +void selectCRXTrack(unsigned short maxTrack); int parseCR3(unsigned long long oAtomList, unsigned long long szAtomList, short &nesting, - char *AtomNameStack, short &nTrack, short &TrackType); -int crxDecodePlane(void *p, uint32_t planeNumber); + char *AtomNameStack, unsigned short &nTrack, short &TrackType); +bool crxDecodePlane(void *p, uint32_t planeNumber); void crxLoadDecodeLoop(void *img, int nPlanes); void crxConvertPlaneLineDf(void *p, int imageRow); void crxLoadFinalizeLoopE3(void *p, int planeHeight); void crxLoadRaw(); -int crxParseImageHeader(uchar *cmp1TagData, int nTrack); +bool crxParseImageHeader(uchar *cmp1TagData, unsigned int nTrack); //----------------------------------------------------------------------------- }; diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index d547d3431..538858a9a 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -21,11 +21,9 @@ #include "rawimagesource.h" #include "rawimage.h" -#include "mytime.h" #include "rt_math.h" #include "color.h" #include "../rtgui/multilangmgr.h" -#include "sleef.h" #include "opthelper.h" #include "median.h" //#define BENCHMARK @@ -39,16 +37,6 @@ using namespace std; namespace rtengine { -#undef ABS - -#define ABS(a) ((a)<0?-(a):(a)) -#define CLIREF(x) LIM(x,-200000.0f,200000.0f) // avoid overflow : do not act directly on image[] or pix[] -#define x1125(a) (a + xdivf(a, 3)) -#define x0875(a) (a - xdivf(a, 3)) -#define x0250(a) xdivf(a, 2) -#define x00625(a) xdivf(a, 4) -#define x0125(a) xdivf(a, 3) - #undef fc #define fc(row,col) \ (ri->get_filters() >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) @@ -210,628 +198,6 @@ void RawImageSource::border_interpolate( int winw, int winh, int lborders, const } -// LSMME demosaicing algorithm -// L. Zhang and X. Wu, -// Color demozaicing via directional Linear Minimum Mean Square-error Estimation, -// IEEE Trans. on Image Processing, vol. 14, pp. 2167-2178, -// Dec. 2005. -// Adapted to RawTherapee by Jacques Desmis 3/2013 -// Improved speed and reduced memory consumption by Ingo Weyrich 2/2015 -//TODO Tiles to reduce memory consumption -void RawImageSource::lmmse_interpolate_omp(int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations) -{ - const int width = winw, height = winh; - const int ba = 10; - const int rr1 = height + 2 * ba; - const int cc1 = width + 2 * ba; - const int w1 = cc1; - const int w2 = 2 * w1; - const int w3 = 3 * w1; - const int w4 = 4 * w1; - float h0, h1, h2, h3, h4, hs; - h0 = 1.0f; - h1 = exp( -1.0f / 8.0f); - h2 = exp( -4.0f / 8.0f); - h3 = exp( -9.0f / 8.0f); - h4 = exp(-16.0f / 8.0f); - hs = h0 + 2.0f * (h1 + h2 + h3 + h4); - h0 /= hs; - h1 /= hs; - h2 /= hs; - h3 /= hs; - h4 /= hs; - int passref = 0; - int iter = 0; - - if(iterations <= 4) { - iter = iterations - 1; - passref = 0; - } else if (iterations <= 6) { - iter = 3; - passref = iterations - 4; - } else if (iterations <= 8) { - iter = 3; - passref = iterations - 6; - } - - bool applyGamma = true; - - if(iterations == 0) { - applyGamma = false; - iter = 0; - } else { - applyGamma = true; - } - - float *rix[5]; - float *qix[5]; - float *buffer = (float *)calloc(static_cast(rr1) * cc1 * 5 * sizeof(float), 1); - - if(buffer == nullptr) { // allocation of big block of memory failed, try to get 5 smaller ones - printf("lmmse_interpolate_omp: allocation of big memory block failed, try to get 5 smaller ones now...\n"); - bool allocationFailed = false; - - for(int i = 0; i < 5; i++) { - qix[i] = (float *)calloc(static_cast(rr1) * cc1 * sizeof(float), 1); - - if(!qix[i]) { // allocation of at least one small block failed - allocationFailed = true; - } - } - - if(allocationFailed) { // fall back to igv_interpolate - printf("lmmse_interpolate_omp: allocation of 5 small memory blocks failed, falling back to igv_interpolate...\n"); - - for(int i = 0; i < 5; i++) { // free the already allocated buffers - if(qix[i]) { - free(qix[i]); - } - } - - igv_interpolate(winw, winh); - return; - } - } else { - qix[0] = buffer; - - for(int i = 1; i < 5; i++) { - qix[i] = qix[i - 1] + rr1 * cc1; - } - } - - if (plistener) { - plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_LMMSE"))); - plistener->setProgress (0.0); - } - - - LUTf *gamtab; - - if(applyGamma) { - gamtab = &(Color::gammatab_24_17a); - } else { - gamtab = new LUTf(65536, LUT_CLIP_ABOVE | LUT_CLIP_BELOW); - gamtab->makeIdentity(65535.f); - } - - -#ifdef _OPENMP - #pragma omp parallel private(rix) -#endif - { -#ifdef _OPENMP - #pragma omp for -#endif - - for (int rrr = ba; rrr < rr1 - ba; rrr++) { - for (int ccc = ba, row = rrr - ba; ccc < cc1 - ba; ccc++) { - int col = ccc - ba; - float *rix = qix[4] + rrr * cc1 + ccc; - rix[0] = (*gamtab)[rawData[row][col]]; - } - } - -#ifdef _OPENMP - #pragma omp single -#endif - { - if (plistener) { - plistener->setProgress (0.1); - } - } - - // G-R(B) -#ifdef _OPENMP - #pragma omp for schedule(dynamic,16) -#endif - - for (int rr = 2; rr < rr1 - 2; rr++) { - // G-R(B) at R(B) location - for (int cc = 2 + (FC(rr, 2) & 1); cc < cc1 - 2; cc += 2) { - rix[4] = qix[4] + rr * cc1 + cc; - float v0 = x00625(rix[4][-w1 - 1] + rix[4][-w1 + 1] + rix[4][w1 - 1] + rix[4][w1 + 1]) + x0250(rix[4][0]); - // horizontal - rix[0] = qix[0] + rr * cc1 + cc; - rix[0][0] = - x0250(rix[4][ -2] + rix[4][ 2]) + xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]); - float Y = v0 + xdiv2f(rix[0][0]); - - if (rix[4][0] > 1.75f * Y) { - rix[0][0] = median(rix[0][0], rix[4][ -1], rix[4][ 1]); - } else { - rix[0][0] = LIM(rix[0][0], 0.0f, 1.0f); - } - - rix[0][0] -= rix[4][0]; - // vertical - rix[1] = qix[1] + rr * cc1 + cc; - rix[1][0] = -x0250(rix[4][-w2] + rix[4][w2]) + xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]); - Y = v0 + xdiv2f(rix[1][0]); - - if (rix[4][0] > 1.75f * Y) { - rix[1][0] = median(rix[1][0], rix[4][-w1], rix[4][w1]); - } else { - rix[1][0] = LIM(rix[1][0], 0.0f, 1.0f); - } - - rix[1][0] -= rix[4][0]; - } - - // G-R(B) at G location - for (int ccc = 2 + (FC(rr, 3) & 1); ccc < cc1 - 2; ccc += 2) { - rix[0] = qix[0] + rr * cc1 + ccc; - rix[1] = qix[1] + rr * cc1 + ccc; - rix[4] = qix[4] + rr * cc1 + ccc; - rix[0][0] = x0250(rix[4][ -2] + rix[4][ 2]) - xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]); - rix[1][0] = x0250(rix[4][-w2] + rix[4][w2]) - xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]); - rix[0][0] = LIM(rix[0][0], -1.0f, 0.0f) + rix[4][0]; - rix[1][0] = LIM(rix[1][0], -1.0f, 0.0f) + rix[4][0]; - } - } - -#ifdef _OPENMP - #pragma omp single -#endif - { - if (plistener) { - plistener->setProgress (0.2); - } - } - - - // apply low pass filter on differential colors -#ifdef _OPENMP - #pragma omp for -#endif - - for (int rr = 4; rr < rr1 - 4; rr++) - for (int cc = 4; cc < cc1 - 4; cc++) { - rix[0] = qix[0] + rr * cc1 + cc; - rix[2] = qix[2] + rr * cc1 + cc; - rix[2][0] = h0 * rix[0][0] + h1 * (rix[0][ -1] + rix[0][ 1]) + h2 * (rix[0][ -2] + rix[0][ 2]) + h3 * (rix[0][ -3] + rix[0][ 3]) + h4 * (rix[0][ -4] + rix[0][ 4]); - rix[1] = qix[1] + rr * cc1 + cc; - rix[3] = qix[3] + rr * cc1 + cc; - rix[3][0] = h0 * rix[1][0] + h1 * (rix[1][-w1] + rix[1][w1]) + h2 * (rix[1][-w2] + rix[1][w2]) + h3 * (rix[1][-w3] + rix[1][w3]) + h4 * (rix[1][-w4] + rix[1][w4]); - } - -#ifdef _OPENMP - #pragma omp single -#endif - { - if (plistener) { - plistener->setProgress (0.3); - } - } - - // interpolate G-R(B) at R(B) -#ifdef _OPENMP - #pragma omp for -#endif - - for (int rr = 4; rr < rr1 - 4; rr++) { - int cc = 4 + (FC(rr, 4) & 1); -#ifdef __SSE2__ - __m128 p1v, p2v, p3v, p4v, p5v, p6v, p7v, p8v, p9v, muv, vxv, vnv, xhv, vhv, xvv, vvv; - __m128 epsv = _mm_set1_ps(1e-7); - __m128 ninev = _mm_set1_ps(9.f); - - for (; cc < cc1 - 10; cc += 8) { - rix[0] = qix[0] + rr * cc1 + cc; - rix[1] = qix[1] + rr * cc1 + cc; - rix[2] = qix[2] + rr * cc1 + cc; - rix[3] = qix[3] + rr * cc1 + cc; - rix[4] = qix[4] + rr * cc1 + cc; - // horizontal - p1v = LC2VFU(rix[2][-4]); - p2v = LC2VFU(rix[2][-3]); - p3v = LC2VFU(rix[2][-2]); - p4v = LC2VFU(rix[2][-1]); - p5v = LC2VFU(rix[2][ 0]); - p6v = LC2VFU(rix[2][ 1]); - p7v = LC2VFU(rix[2][ 2]); - p8v = LC2VFU(rix[2][ 3]); - p9v = LC2VFU(rix[2][ 4]); - muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev; - vxv = epsv + SQRV(p1v - muv) + SQRV(p2v - muv) + SQRV(p3v - muv) + SQRV(p4v - muv) + SQRV(p5v - muv) + SQRV(p6v - muv) + SQRV(p7v - muv) + SQRV(p8v - muv) + SQRV(p9v - muv); - p1v -= LC2VFU(rix[0][-4]); - p2v -= LC2VFU(rix[0][-3]); - p3v -= LC2VFU(rix[0][-2]); - p4v -= LC2VFU(rix[0][-1]); - p5v -= LC2VFU(rix[0][ 0]); - p6v -= LC2VFU(rix[0][ 1]); - p7v -= LC2VFU(rix[0][ 2]); - p8v -= LC2VFU(rix[0][ 3]); - p9v -= LC2VFU(rix[0][ 4]); - vnv = epsv + SQRV(p1v) + SQRV(p2v) + SQRV(p3v) + SQRV(p4v) + SQRV(p5v) + SQRV(p6v) + SQRV(p7v) + SQRV(p8v) + SQRV(p9v); - xhv = (LC2VFU(rix[0][0]) * vxv + LC2VFU(rix[2][0]) * vnv) / (vxv + vnv); - vhv = vxv * vnv / (vxv + vnv); - - // vertical - p1v = LC2VFU(rix[3][-w4]); - p2v = LC2VFU(rix[3][-w3]); - p3v = LC2VFU(rix[3][-w2]); - p4v = LC2VFU(rix[3][-w1]); - p5v = LC2VFU(rix[3][ 0]); - p6v = LC2VFU(rix[3][ w1]); - p7v = LC2VFU(rix[3][ w2]); - p8v = LC2VFU(rix[3][ w3]); - p9v = LC2VFU(rix[3][ w4]); - muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev; - vxv = epsv + SQRV(p1v - muv) + SQRV(p2v - muv) + SQRV(p3v - muv) + SQRV(p4v - muv) + SQRV(p5v - muv) + SQRV(p6v - muv) + SQRV(p7v - muv) + SQRV(p8v - muv) + SQRV(p9v - muv); - p1v -= LC2VFU(rix[1][-w4]); - p2v -= LC2VFU(rix[1][-w3]); - p3v -= LC2VFU(rix[1][-w2]); - p4v -= LC2VFU(rix[1][-w1]); - p5v -= LC2VFU(rix[1][ 0]); - p6v -= LC2VFU(rix[1][ w1]); - p7v -= LC2VFU(rix[1][ w2]); - p8v -= LC2VFU(rix[1][ w3]); - p9v -= LC2VFU(rix[1][ w4]); - vnv = epsv + SQRV(p1v) + SQRV(p2v) + SQRV(p3v) + SQRV(p4v) + SQRV(p5v) + SQRV(p6v) + SQRV(p7v) + SQRV(p8v) + SQRV(p9v); - xvv = (LC2VFU(rix[1][0]) * vxv + LC2VFU(rix[3][0]) * vnv) / (vxv + vnv); - vvv = vxv * vnv / (vxv + vnv); - // interpolated G-R(B) - muv = (xhv * vvv + xvv * vhv) / (vhv + vvv); - STC2VFU(rix[4][0], muv); - } - -#endif - - for (; cc < cc1 - 4; cc += 2) { - rix[0] = qix[0] + rr * cc1 + cc; - rix[1] = qix[1] + rr * cc1 + cc; - rix[2] = qix[2] + rr * cc1 + cc; - rix[3] = qix[3] + rr * cc1 + cc; - rix[4] = qix[4] + rr * cc1 + cc; - // horizontal - float p1 = rix[2][-4]; - float p2 = rix[2][-3]; - float p3 = rix[2][-2]; - float p4 = rix[2][-1]; - float p5 = rix[2][ 0]; - float p6 = rix[2][ 1]; - float p7 = rix[2][ 2]; - float p8 = rix[2][ 3]; - float p9 = rix[2][ 4]; - float mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f; - float vx = 1e-7 + SQR(p1 - mu) + SQR(p2 - mu) + SQR(p3 - mu) + SQR(p4 - mu) + SQR(p5 - mu) + SQR(p6 - mu) + SQR(p7 - mu) + SQR(p8 - mu) + SQR(p9 - mu); - p1 -= rix[0][-4]; - p2 -= rix[0][-3]; - p3 -= rix[0][-2]; - p4 -= rix[0][-1]; - p5 -= rix[0][ 0]; - p6 -= rix[0][ 1]; - p7 -= rix[0][ 2]; - p8 -= rix[0][ 3]; - p9 -= rix[0][ 4]; - float vn = 1e-7 + SQR(p1) + SQR(p2) + SQR(p3) + SQR(p4) + SQR(p5) + SQR(p6) + SQR(p7) + SQR(p8) + SQR(p9); - float xh = (rix[0][0] * vx + rix[2][0] * vn) / (vx + vn); - float vh = vx * vn / (vx + vn); - - // vertical - p1 = rix[3][-w4]; - p2 = rix[3][-w3]; - p3 = rix[3][-w2]; - p4 = rix[3][-w1]; - p5 = rix[3][ 0]; - p6 = rix[3][ w1]; - p7 = rix[3][ w2]; - p8 = rix[3][ w3]; - p9 = rix[3][ w4]; - mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f; - vx = 1e-7 + SQR(p1 - mu) + SQR(p2 - mu) + SQR(p3 - mu) + SQR(p4 - mu) + SQR(p5 - mu) + SQR(p6 - mu) + SQR(p7 - mu) + SQR(p8 - mu) + SQR(p9 - mu); - p1 -= rix[1][-w4]; - p2 -= rix[1][-w3]; - p3 -= rix[1][-w2]; - p4 -= rix[1][-w1]; - p5 -= rix[1][ 0]; - p6 -= rix[1][ w1]; - p7 -= rix[1][ w2]; - p8 -= rix[1][ w3]; - p9 -= rix[1][ w4]; - vn = 1e-7 + SQR(p1) + SQR(p2) + SQR(p3) + SQR(p4) + SQR(p5) + SQR(p6) + SQR(p7) + SQR(p8) + SQR(p9); - float xv = (rix[1][0] * vx + rix[3][0] * vn) / (vx + vn); - float vv = vx * vn / (vx + vn); - // interpolated G-R(B) - rix[4][0] = (xh * vv + xv * vh) / (vh + vv); - } - } - -#ifdef _OPENMP - #pragma omp single -#endif - { - if (plistener) { - plistener->setProgress (0.4); - } - } - - // copy CFA values -#ifdef _OPENMP - #pragma omp for -#endif - - for (int rr = 0; rr < rr1; rr++) - for (int cc = 0, row = rr - ba; cc < cc1; cc++) { - int col = cc - ba; - int c = FC(rr, cc); - rix[c] = qix[c] + rr * cc1 + cc; - - if ((row >= 0) & (row < height) & (col >= 0) & (col < width)) { - rix[c][0] = (*gamtab)[rawData[row][col]]; - } else { - rix[c][0] = 0.f; - } - - if (c != 1) { - rix[1] = qix[1] + rr * cc1 + cc; - rix[4] = qix[4] + rr * cc1 + cc; - rix[1][0] = rix[c][0] + rix[4][0]; - } - } - -#ifdef _OPENMP - #pragma omp single -#endif - { - if (plistener) { - plistener->setProgress (0.5); - } - } - - // bilinear interpolation for R/B - // interpolate R/B at G location -#ifdef _OPENMP - #pragma omp for -#endif - - for (int rr = 1; rr < rr1 - 1; rr++) - for (int cc = 1 + (FC(rr, 2) & 1), c = FC(rr, cc + 1); cc < cc1 - 1; cc += 2) { - rix[c] = qix[c] + rr * cc1 + cc; - rix[1] = qix[1] + rr * cc1 + cc; - rix[c][0] = rix[1][0] + xdiv2f(rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1]); - c = 2 - c; - rix[c] = qix[c] + rr * cc1 + cc; - rix[c][0] = rix[1][0] + xdiv2f(rix[c][-w1] - rix[1][-w1] + rix[c][w1] - rix[1][w1]); - c = 2 - c; - } - -#ifdef _OPENMP - #pragma omp single -#endif - { - if (plistener) { - plistener->setProgress (0.6); - } - } - - // interpolate R/B at B/R location -#ifdef _OPENMP - #pragma omp for -#endif - - for (int rr = 1; rr < rr1 - 1; rr++) - for (int cc = 1 + (FC(rr, 1) & 1), c = 2 - FC(rr, cc); cc < cc1 - 1; cc += 2) { - rix[c] = qix[c] + rr * cc1 + cc; - rix[1] = qix[1] + rr * cc1 + cc; - rix[c][0] = rix[1][0] + x0250(rix[c][-w1] - rix[1][-w1] + rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1] + rix[c][ w1] - rix[1][ w1]); - } - -#ifdef _OPENMP - #pragma omp single -#endif - { - if (plistener) { - plistener->setProgress (0.7); - } - } - - }// End of parallelization 1 - - // median filter/ - for (int pass = 0; pass < iter; pass++) { - // Apply 3x3 median filter - // Compute median(R-G) and median(B-G) - -#ifdef _OPENMP - #pragma omp parallel for private(rix) -#endif - - for (int rr = 1; rr < rr1 - 1; rr++) { - for (int c = 0; c < 3; c += 2) { - int d = c + 3 - (c == 0 ? 0 : 1); - int cc = 1; -#ifdef __SSE2__ - - for (; cc < cc1 - 4; cc += 4) { - rix[d] = qix[d] + rr * cc1 + cc; - rix[c] = qix[c] + rr * cc1 + cc; - rix[1] = qix[1] + rr * cc1 + cc; - // Assign 3x3 differential color values - const std::array p = { - LVFU(rix[c][-w1 - 1]) - LVFU(rix[1][-w1 - 1]), - LVFU(rix[c][-w1]) - LVFU(rix[1][-w1]), - LVFU(rix[c][-w1 + 1]) - LVFU(rix[1][-w1 + 1]), - LVFU(rix[c][ -1]) - LVFU(rix[1][ -1]), - LVFU(rix[c][ 0]) - LVFU(rix[1][ 0]), - LVFU(rix[c][ 1]) - LVFU(rix[1][ 1]), - LVFU(rix[c][ w1 - 1]) - LVFU(rix[1][ w1 - 1]), - LVFU(rix[c][ w1]) - LVFU(rix[1][ w1]), - LVFU(rix[c][ w1 + 1]) - LVFU(rix[1][ w1 + 1]) - }; - _mm_storeu_ps(&rix[d][0], median(p)); - } - -#endif - - for (; cc < cc1 - 1; cc++) { - rix[d] = qix[d] + rr * cc1 + cc; - rix[c] = qix[c] + rr * cc1 + cc; - rix[1] = qix[1] + rr * cc1 + cc; - // Assign 3x3 differential color values - const std::array p = { - rix[c][-w1 - 1] - rix[1][-w1 - 1], - rix[c][-w1] - rix[1][-w1], - rix[c][-w1 + 1] - rix[1][-w1 + 1], - rix[c][ -1] - rix[1][ -1], - rix[c][ 0] - rix[1][ 0], - rix[c][ 1] - rix[1][ 1], - rix[c][ w1 - 1] - rix[1][ w1 - 1], - rix[c][ w1] - rix[1][ w1], - rix[c][ w1 + 1] - rix[1][ w1 + 1] - }; - rix[d][0] = median(p); - } - } - } - - // red/blue at GREEN pixel locations & red/blue and green at BLUE/RED pixel locations -#ifdef _OPENMP - #pragma omp parallel for private (rix) -#endif - - for (int rr = 0; rr < rr1; rr++) { - rix[0] = qix[0] + rr * cc1; - rix[1] = qix[1] + rr * cc1; - rix[2] = qix[2] + rr * cc1; - rix[3] = qix[3] + rr * cc1; - rix[4] = qix[4] + rr * cc1; - int c0 = FC(rr, 0); - int c1 = FC(rr, 1); - - if(c0 == 1) { - c1 = 2 - c1; - int d = c1 + 3 - (c1 == 0 ? 0 : 1); - int cc; - - for (cc = 0; cc < cc1 - 1; cc += 2) { - rix[0][0] = rix[1][0] + rix[3][0]; - rix[2][0] = rix[1][0] + rix[4][0]; - rix[0]++; - rix[1]++; - rix[2]++; - rix[3]++; - rix[4]++; - rix[c1][0] = rix[1][0] + rix[d][0]; - rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]); - rix[0]++; - rix[1]++; - rix[2]++; - rix[3]++; - rix[4]++; - } - - if(cc < cc1) { // remaining pixel, only if width is odd - rix[0][0] = rix[1][0] + rix[3][0]; - rix[2][0] = rix[1][0] + rix[4][0]; - } - } else { - c0 = 2 - c0; - int d = c0 + 3 - (c0 == 0 ? 0 : 1); - int cc; - - for (cc = 0; cc < cc1 - 1; cc += 2) { - rix[c0][0] = rix[1][0] + rix[d][0]; - rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]); - rix[0]++; - rix[1]++; - rix[2]++; - rix[3]++; - rix[4]++; - rix[0][0] = rix[1][0] + rix[3][0]; - rix[2][0] = rix[1][0] + rix[4][0]; - rix[0]++; - rix[1]++; - rix[2]++; - rix[3]++; - rix[4]++; - } - - if(cc < cc1) { // remaining pixel, only if width is odd - rix[c0][0] = rix[1][0] + rix[d][0]; - rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]); - } - } - } - } - - if (plistener) { - plistener->setProgress (0.8); - } - - if(applyGamma) { - gamtab = &(Color::igammatab_24_17); - } else { - gamtab->makeIdentity(); - } - - array2D* rgb[3]; - rgb[0] = &red; - rgb[1] = &green; - rgb[2] = &blue; - - // copy result back to image matrix -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int row = 0; row < height; row++) { - for (int col = 0, rr = row + ba; col < width; col++) { - int cc = col + ba; - int c = FC(row, col); - - for (int ii = 0; ii < 3; ii++) - if (ii != c) { - float *rix = qix[ii] + rr * cc1 + cc; - (*(rgb[ii]))[row][col] = (*gamtab)[65535.f * rix[0]]; - } else { - (*(rgb[ii]))[row][col] = CLIP(rawData[row][col]); - } - } - } - - if (plistener) { - plistener->setProgress (1.0); - } - - if(buffer) { - free(buffer); - } else - for(int i = 0; i < 5; i++) { - free(qix[i]); - } - - if(!applyGamma) { - delete gamtab; - } - - if(iterations > 4 && iterations <= 6) { - refinement(passref); - } else if(iterations > 6) { - refinement_lassus(passref); - } - -} - /*** * * Bayer CFA Demosaicing using Integrated Gaussian Vector on Color Differences @@ -849,7 +215,6 @@ void RawImageSource::lmmse_interpolate_omp(int winw, int winh, array2D &r // Adapted to RawTherapee by Jacques Desmis 3/2013 // SSE version by Ingo Weyrich 5/2013 #ifdef __SSE2__ -#define CLIPV(a) vclampf(a,zerov,c65535v) void RawImageSource::igv_interpolate(int winw, int winh) { static const float eps = 1e-5f, epssq = 1e-5f; //mod epssq -10f =>-5f Jacques 3/2013 to prevent artifact (divide by zero) @@ -918,9 +283,9 @@ void RawImageSource::igv_interpolate(int winw, int winh) for (col = 0, indx = row * width + col; col < width - 7; col += 8, indx += 8) { temp1v = LVFU( rawData[row][col] ); - temp1v = CLIPV( temp1v ); + temp1v = vmaxf(temp1v, ZEROV); temp2v = LVFU( rawData[row][col + 4] ); - temp2v = CLIPV( temp2v ); + temp2v = vmaxf(temp2v, ZEROV); tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 2, 0, 2, 0 ) ); _mm_storeu_ps( &dest1[indx >> 1], tempv ); tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 3, 1, 3, 1 ) ); @@ -928,10 +293,10 @@ void RawImageSource::igv_interpolate(int winw, int winh) } for (; col < width; col++, indx += 2) { - dest1[indx >> 1] = CLIP(rawData[row][col]); //rawData = RT data + dest1[indx >> 1] = std::max(0.f, rawData[row][col]); //rawData = RT data col++; if(col < width) - dest2[indx >> 1] = CLIP(rawData[row][col]); //rawData = RT data + dest2[indx >> 1] = std::max(0.f, rawData[row][col]); //rawData = RT data } } @@ -1190,42 +555,42 @@ void RawImageSource::igv_interpolate(int winw, int winh) temp2v = LVFU( src2[(indx + 1) >> 1] ); tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 1, 0, 1, 0 ) ); tempv = _mm_shuffle_ps( tempv, tempv, _MM_SHUFFLE( 3, 1, 2, 0 ) ); - _mm_storeu_ps( &green[row][col], CLIPV( tempv )); + _mm_storeu_ps( &green[row][col], vmaxf(tempv, ZEROV)); temp5v = LVFU(redsrc0[indx >> 1]); temp6v = LVFU(redsrc1[(indx + 1) >> 1]); temp3v = _mm_shuffle_ps( temp5v, temp6v, _MM_SHUFFLE( 1, 0, 1, 0 ) ); temp3v = _mm_shuffle_ps( temp3v, temp3v, _MM_SHUFFLE( 3, 1, 2, 0 ) ); - temp3v = CLIPV( tempv - c65535v * temp3v ); + temp3v = vmaxf(tempv - c65535v * temp3v, ZEROV); _mm_storeu_ps( &red[row][col], temp3v); temp7v = LVFU(bluesrc0[indx >> 1]); temp8v = LVFU(bluesrc1[(indx + 1) >> 1]); temp4v = _mm_shuffle_ps( temp7v, temp8v, _MM_SHUFFLE( 1, 0, 1, 0 ) ); temp4v = _mm_shuffle_ps( temp4v, temp4v, _MM_SHUFFLE( 3, 1, 2, 0 ) ); - temp4v = CLIPV( tempv - c65535v * temp4v ); + temp4v = vmaxf(tempv - c65535v * temp4v, ZEROV); _mm_storeu_ps( &blue[row][col], temp4v); tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 3, 2, 3, 2 ) ); tempv = _mm_shuffle_ps( tempv, tempv, _MM_SHUFFLE( 3, 1, 2, 0 ) ); - _mm_storeu_ps( &green[row][col + 4], CLIPV( tempv )); + _mm_storeu_ps( &green[row][col + 4], vmaxf(tempv, ZEROV)); temp3v = _mm_shuffle_ps( temp5v, temp6v, _MM_SHUFFLE( 3, 2, 3, 2 ) ); temp3v = _mm_shuffle_ps( temp3v, temp3v, _MM_SHUFFLE( 3, 1, 2, 0 ) ); - temp3v = CLIPV( tempv - c65535v * temp3v ); + temp3v = vmaxf(tempv - c65535v * temp3v, ZEROV); _mm_storeu_ps( &red[row][col + 4], temp3v); temp4v = _mm_shuffle_ps( temp7v, temp8v, _MM_SHUFFLE( 3, 2, 3, 2 ) ); temp4v = _mm_shuffle_ps( temp4v, temp4v, _MM_SHUFFLE( 3, 1, 2, 0 ) ); - temp4v = CLIPV( tempv - c65535v * temp4v ); + temp4v = vmaxf(tempv - c65535v * temp4v, ZEROV); _mm_storeu_ps( &blue[row][col + 4], temp4v); } for(; col < width - 7; col++, indx += 2) { - red [row][col] = CLIP(src1[indx >> 1] - 65535.f * redsrc0[indx >> 1]); - green[row][col] = CLIP(src1[indx >> 1]); - blue [row][col] = CLIP(src1[indx >> 1] - 65535.f * bluesrc0[indx >> 1]); + red [row][col] = std::max(0.f, src1[indx >> 1] - 65535.f * redsrc0[indx >> 1]); + green[row][col] = std::max(0.f, src1[indx >> 1]); + blue [row][col] = std::max(0.f, src1[indx >> 1] - 65535.f * bluesrc0[indx >> 1]); col++; - red [row][col] = CLIP(src2[(indx + 1) >> 1] - 65535.f * redsrc1[(indx + 1) >> 1]); - green[row][col] = CLIP(src2[(indx + 1) >> 1]); - blue [row][col] = CLIP(src2[(indx + 1) >> 1] - 65535.f * bluesrc1[(indx + 1) >> 1]); + red [row][col] = std::max(0.f, src2[(indx + 1) >> 1] - 65535.f * redsrc1[(indx + 1) >> 1]); + green[row][col] = std::max(0.f, src2[(indx + 1) >> 1]); + blue [row][col] = std::max(0.f, src2[(indx + 1) >> 1] - 65535.f * bluesrc1[(indx + 1) >> 1]); } } }// End of parallelization @@ -1240,7 +605,6 @@ void RawImageSource::igv_interpolate(int winw, int winh) free(vdif); free(hdif); } -#undef CLIPV #else void RawImageSource::igv_interpolate(int winw, int winh) { @@ -1283,7 +647,7 @@ void RawImageSource::igv_interpolate(int winw, int winh) for (int row = 0; row < height - 0; row++) for (int col = 0, indx = row * width + col; col < width - 0; col++, indx++) { int c = FC(row, col); - rgb[c][indx] = CLIP(rawData[row][col]); //rawData = RT data + rgb[c][indx] = std::max(0.f, rawData[row][col]); //rawData = RT data } #ifdef _OPENMP @@ -1482,9 +846,9 @@ void RawImageSource::igv_interpolate(int winw, int winh) for(int row = 7; row < height - 7; row++) for(int col = 7, indx = row * width + col; col < width - 7; col++, indx++) { - red [row][col] = CLIP(rgb[1][indx] - 65535.f * chr[0][indx]); - green[row][col] = CLIP(rgb[1][indx]); - blue [row][col] = CLIP(rgb[1][indx] - 65535.f * chr[1][indx]); + red [row][col] = std::max(0.f, rgb[1][indx] - 65535.f * chr[0][indx]); + green[row][col] = std::max(0.f, rgb[1][indx]); + blue [row][col] = std::max(0.f, rgb[1][indx] - 65535.f * chr[1][indx]); } }// End of parallelization border_interpolate(winw, winh, 8, rawData, red, green, blue); @@ -1553,357 +917,6 @@ void RawImageSource::nodemosaic(bool bw) } } -/* - Refinement based on EECI demosaicing algorithm by L. Chang and Y.P. Tan - Paul Lee - Adapted for RawTherapee - Jacques Desmis 04/2013 -*/ - -#ifdef __SSE2__ -#define CLIPV(a) vclampf(a,ZEROV,c65535v) -#endif -void RawImageSource::refinement(int PassCount) -{ - MyTime t1e, t2e; - t1e.set(); - - int width = W; - int height = H; - int w1 = width; - int w2 = 2 * w1; - - if (plistener) { - plistener->setProgressStr (M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE")); - } - - array2D *rgb[3]; - rgb[0] = &red; - rgb[1] = &green; - rgb[2] = &blue; - - for (int b = 0; b < PassCount; b++) { - if (plistener) { - plistener->setProgress ((float)b / PassCount); - } - - -#ifdef _OPENMP - #pragma omp parallel -#endif - { - float *pix[3]; - - /* Reinforce interpolated green pixels on RED/BLUE pixel locations */ -#ifdef _OPENMP - #pragma omp for -#endif - - for (int row = 2; row < height - 2; row++) { - int col = 2 + (FC(row, 2) & 1); - int c = FC(row, col); -#ifdef __SSE2__ - __m128 dLv, dRv, dUv, dDv, v0v; - __m128 onev = _mm_set1_ps(1.f); - __m128 zd5v = _mm_set1_ps(0.5f); - __m128 c65535v = _mm_set1_ps(65535.f); - - for (; col < width - 8; col += 8) { - int indx = row * width + col; - pix[c] = (float*)(*rgb[c]) + indx; - pix[1] = (float*)(*rgb[1]) + indx; - dLv = onev / (onev + vabsf(LC2VFU(pix[c][ -2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1]))); - dRv = onev / (onev + vabsf(LC2VFU(pix[c][ 2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1]))); - dUv = onev / (onev + vabsf(LC2VFU(pix[c][-w2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1]))); - dDv = onev / (onev + vabsf(LC2VFU(pix[c][ w2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1]))); - v0v = CLIPV(LC2VFU(pix[c][0]) + zd5v + ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv)); - STC2VFU(pix[1][0], v0v); - } - -#endif - - for (; col < width - 2; col += 2) { - int indx = row * width + col; - pix[c] = (float*)(*rgb[c]) + indx; - pix[1] = (float*)(*rgb[1]) + indx; - float dL = 1.f / (1.f + fabsf(pix[c][ -2] - pix[c][0]) + fabsf(pix[1][ 1] - pix[1][ -1])); - float dR = 1.f / (1.f + fabsf(pix[c][ 2] - pix[c][0]) + fabsf(pix[1][ 1] - pix[1][ -1])); - float dU = 1.f / (1.f + fabsf(pix[c][-w2] - pix[c][0]) + fabsf(pix[1][w1] - pix[1][-w1])); - float dD = 1.f / (1.f + fabsf(pix[c][ w2] - pix[c][0]) + fabsf(pix[1][w1] - pix[1][-w1])); - float v0 = (pix[c][0] + 0.5f + ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD)); - pix[1][0] = CLIP(v0); - } - } - - /* Reinforce interpolated red/blue pixels on GREEN pixel locations */ -#ifdef _OPENMP - #pragma omp for -#endif - - for (int row = 2; row < height - 2; row++) { - int col = 2 + (FC(row, 3) & 1); - int c = FC(row, col + 1); -#ifdef __SSE2__ - __m128 dLv, dRv, dUv, dDv, v0v; - __m128 onev = _mm_set1_ps(1.f); - __m128 zd5v = _mm_set1_ps(0.5f); - __m128 c65535v = _mm_set1_ps(65535.f); - - for (; col < width - 8; col += 8) { - int indx = row * width + col; - pix[1] = (float*)(*rgb[1]) + indx; - - for (int i = 0; i < 2; c = 2 - c, i++) { - pix[c] = (float*)(*rgb[c]) + indx; - dLv = onev / (onev + vabsf(LC2VFU(pix[1][ -2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][ 1]) - LC2VFU(pix[c][ -1]))); - dRv = onev / (onev + vabsf(LC2VFU(pix[1][ 2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][ 1]) - LC2VFU(pix[c][ -1]))); - dUv = onev / (onev + vabsf(LC2VFU(pix[1][-w2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][w1]) - LC2VFU(pix[c][-w1]))); - dDv = onev / (onev + vabsf(LC2VFU(pix[1][ w2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][w1]) - LC2VFU(pix[c][-w1]))); - v0v = CLIPV(LC2VFU(pix[1][0]) + zd5v - ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv)); - STC2VFU(pix[c][0], v0v); - } - } - -#endif - - for (; col < width - 2; col += 2) { - int indx = row * width + col; - pix[1] = (float*)(*rgb[1]) + indx; - - for (int i = 0; i < 2; c = 2 - c, i++) { - pix[c] = (float*)(*rgb[c]) + indx; - float dL = 1.f / (1.f + fabsf(pix[1][ -2] - pix[1][0]) + fabsf(pix[c][ 1] - pix[c][ -1])); - float dR = 1.f / (1.f + fabsf(pix[1][ 2] - pix[1][0]) + fabsf(pix[c][ 1] - pix[c][ -1])); - float dU = 1.f / (1.f + fabsf(pix[1][-w2] - pix[1][0]) + fabsf(pix[c][w1] - pix[c][-w1])); - float dD = 1.f / (1.f + fabsf(pix[1][ w2] - pix[1][0]) + fabsf(pix[c][w1] - pix[c][-w1])); - float v0 = (pix[1][0] + 0.5f - ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD)); - pix[c][0] = CLIP(v0); - } - } - } - - /* Reinforce integrated red/blue pixels on BLUE/RED pixel locations */ -#ifdef _OPENMP - #pragma omp for -#endif - - for (int row = 2; row < height - 2; row++) { - int col = 2 + (FC(row, 2) & 1); - int c = 2 - FC(row, col); -#ifdef __SSE2__ - __m128 dLv, dRv, dUv, dDv, v0v; - __m128 onev = _mm_set1_ps(1.f); - __m128 zd5v = _mm_set1_ps(0.5f); - __m128 c65535v = _mm_set1_ps(65535.f); - - for (; col < width - 8; col += 8) { - int indx = row * width + col; - pix[0] = (float*)(*rgb[0]) + indx; - pix[1] = (float*)(*rgb[1]) + indx; - pix[2] = (float*)(*rgb[2]) + indx; - int d = 2 - c; - dLv = onev / (onev + vabsf(LC2VFU(pix[d][ -2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1]))); - dRv = onev / (onev + vabsf(LC2VFU(pix[d][ 2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1]))); - dUv = onev / (onev + vabsf(LC2VFU(pix[d][-w2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1]))); - dDv = onev / (onev + vabsf(LC2VFU(pix[d][ w2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1]))); - v0v = CLIPV(LC2VFU(pix[1][0]) + zd5v - ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv)); - STC2VFU(pix[c][0], v0v); - } - -#endif - - for (; col < width - 2; col += 2) { - int indx = row * width + col; - pix[0] = (float*)(*rgb[0]) + indx; - pix[1] = (float*)(*rgb[1]) + indx; - pix[2] = (float*)(*rgb[2]) + indx; - int d = 2 - c; - float dL = 1.f / (1.f + fabsf(pix[d][ -2] - pix[d][0]) + fabsf(pix[1][ 1] - pix[1][ -1])); - float dR = 1.f / (1.f + fabsf(pix[d][ 2] - pix[d][0]) + fabsf(pix[1][ 1] - pix[1][ -1])); - float dU = 1.f / (1.f + fabsf(pix[d][-w2] - pix[d][0]) + fabsf(pix[1][w1] - pix[1][-w1])); - float dD = 1.f / (1.f + fabsf(pix[d][ w2] - pix[d][0]) + fabsf(pix[1][w1] - pix[1][-w1])); - float v0 = (pix[1][0] + 0.5f - ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD)); - pix[c][0] = CLIP(v0); - } - } - } // end parallel - } - - t2e.set(); - - if (settings->verbose) { - printf("Refinement Lee %d usec\n", t2e.etime(t1e)); - } -} -#ifdef __SSE2__ -#undef CLIPV -#endif - - -// Refinement based on EECI demozaicing algorithm by L. Chang and Y.P. Tan -// from "Lassus" : Luis Sanz Rodriguez, adapted by Jacques Desmis - JDC - and Oliver Duis for RawTherapee -// increases the signal to noise ratio (PSNR) # +1 to +2 dB : tested with Dcraw : -// eg: Lighthouse + AMaZE : without refinement:39.96 dB, with refinement:41.86 dB -// reduce color artifacts, improves the interpolation -// but it's relatively slow -// -// Should be DISABLED if it decreases image quality by increases some image noise and generates blocky edges -void RawImageSource::refinement_lassus(int PassCount) -{ - // const int PassCount=1; - - // if (settings->verbose) printf("Refinement\n"); - - MyTime t1e, t2e; - t1e.set(); - int u = W, v = 2 * u, w = 3 * u, x = 4 * u, y = 5 * u; - float (*image)[3]; - image = (float(*)[3]) calloc(static_cast(W) * H, sizeof * image); -#ifdef _OPENMP - #pragma omp parallel shared(image) -#endif - { - // convert red, blue, green to image -#ifdef _OPENMP - #pragma omp for -#endif - - for (int i = 0; i < H; i++) { - for (int j = 0; j < W; j++) { - image[i * W + j][0] = red [i][j]; - image[i * W + j][1] = green[i][j]; - image[i * W + j][2] = blue [i][j]; - } - } - - for (int b = 0; b < PassCount; b++) { - if (plistener) { - plistener->setProgressStr (M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE")); - plistener->setProgress ((float)b / PassCount); - } - - // Reinforce interpolated green pixels on RED/BLUE pixel locations -#ifdef _OPENMP - #pragma omp for -#endif - - for (int row = 6; row < H - 6; row++) { - for (int col = 6 + (FC(row, 2) & 1), c = FC(row, col); col < W - 6; col += 2) { - float (*pix)[3] = image + row * W + col; - - // Cubic Spline Interpolation by Li and Randhawa, modified by Luis Sanz Rodriguez - - float f[4]; - f[0] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[-v][c]) - x0875(pix[0][c]) - x0250(pix[-x][c]))) + fabs(x0875(pix[u][1]) - x1125(pix[-u][1]) + x0250(pix[-w][1])) + fabs(x0875(pix[-w][1]) - x1125(pix[-u][1]) + x0250(pix[-y][1]))); - f[1] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[+2][c]) - x0875(pix[0][c]) - x0250(pix[+4][c]))) + fabs(x0875(pix[1][1]) - x1125(pix[-1][1]) + x0250(pix[+3][1])) + fabs(x0875(pix[+3][1]) - x1125(pix[+1][1]) + x0250(pix[+5][1]))); - f[2] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[-2][c]) - x0875(pix[0][c]) - x0250(pix[-4][c]))) + fabs(x0875(pix[1][1]) - x1125(pix[-1][1]) + x0250(pix[-3][1])) + fabs(x0875(pix[-3][1]) - x1125(pix[-1][1]) + x0250(pix[-5][1]))); - f[3] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[+v][c]) - x0875(pix[0][c]) - x0250(pix[+x][c]))) + fabs(x0875(pix[u][1]) - x1125(pix[-u][1]) + x0250(pix[+w][1])) + fabs(x0875(pix[+w][1]) - x1125(pix[+u][1]) + x0250(pix[+y][1]))); - - float g[4];//CLIREF avoid overflow - g[0] = pix[0][c] + (x0875(CLIREF(pix[-u][1] - pix[-u][c])) + x0125(CLIREF(pix[+u][1] - pix[+u][c]))); - g[1] = pix[0][c] + (x0875(CLIREF(pix[+1][1] - pix[+1][c])) + x0125(CLIREF(pix[-1][1] - pix[-1][c]))); - g[2] = pix[0][c] + (x0875(CLIREF(pix[-1][1] - pix[-1][c])) + x0125(CLIREF(pix[+1][1] - pix[+1][c]))); - g[3] = pix[0][c] + (x0875(CLIREF(pix[+u][1] - pix[+u][c])) + x0125(CLIREF(pix[-u][1] - pix[-u][c]))); - - pix[0][1] = (f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / (f[0] + f[1] + f[2] + f[3]); - - } - } - - // Reinforce interpolated red/blue pixels on GREEN pixel locations -#ifdef _OPENMP - #pragma omp for -#endif - - for (int row = 6; row < H - 6; row++) { - for (int col = 6 + (FC(row, 3) & 1), c = FC(row, col + 1); col < W - 6; col += 2) { - float (*pix)[3] = image + row * W + col; - - for (int i = 0; i < 2; c = 2 - c, i++) { - float f[4]; - f[0] = 1.0f / (1.0f + xmul2f(fabs(x0875(pix[-v][1]) - x1125(pix[0][1]) + x0250(pix[-x][1]))) + fabs(pix[u] [c] - pix[-u][c]) + fabs(pix[-w][c] - pix[-u][c])); - f[1] = 1.0f / (1.0f + xmul2f(fabs(x0875(pix[+2][1]) - x1125(pix[0][1]) + x0250(pix[+4][1]))) + fabs(pix[+1][c] - pix[-1][c]) + fabs(pix[+3][c] - pix[+1][c])); - f[2] = 1.0f / (1.0f + xmul2f(fabs(x0875(pix[-2][1]) - x1125(pix[0][1]) + x0250(pix[-4][1]))) + fabs(pix[+1][c] - pix[-1][c]) + fabs(pix[-3][c] - pix[-1][c])); - f[3] = 1.0f / (1.0f + xmul2f(fabs(x0875(pix[+v][1]) - x1125(pix[0][1]) + x0250(pix[+x][1]))) + fabs(pix[u] [c] - pix[-u][c]) + fabs(pix[+w][c] - pix[+u][c])); - - float g[5];//CLIREF avoid overflow - g[0] = CLIREF(pix[-u][1] - pix[-u][c]); - g[1] = CLIREF(pix[+1][1] - pix[+1][c]); - g[2] = CLIREF(pix[-1][1] - pix[-1][c]); - g[3] = CLIREF(pix[+u][1] - pix[+u][c]); - g[4] = ((f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / (f[0] + f[1] + f[2] + f[3])); - pix[0][c] = pix[0][1] - (0.65f * g[4] + 0.35f * CLIREF(pix[0][1] - pix[0][c])); - } - } - } - - // Reinforce integrated red/blue pixels on BLUE/RED pixel locations -#ifdef _OPENMP - #pragma omp for -#endif - - for (int row = 6; row < H - 6; row++) { - for (int col = 6 + (FC(row, 2) & 1), c = 2 - FC(row, col), d = 2 - c; col < W - 6; col += 2) { - float (*pix)[3] = image + row * W + col; - - float f[4]; - f[0] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[-v][d]) - x0875(pix[0][d]) - x0250(pix[-x][d]))) + fabs(x0875(pix[u][1]) - x1125(pix[-u][1]) + x0250(pix[-w][1])) + fabs(x0875(pix[-w][1]) - x1125(pix[-u][1]) + x0250(pix[-y][1]))); - f[1] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[+2][d]) - x0875(pix[0][d]) - x0250(pix[+4][d]))) + fabs(x0875(pix[1][1]) - x1125(pix[-1][1]) + x0250(pix[+3][1])) + fabs(x0875(pix[+3][1]) - x1125(pix[+1][1]) + x0250(pix[+5][1]))); - f[2] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[-2][d]) - x0875(pix[0][d]) - x0250(pix[-4][d]))) + fabs(x0875(pix[1][1]) - x1125(pix[-1][1]) + x0250(pix[-3][1])) + fabs(x0875(pix[-3][1]) - x1125(pix[-1][1]) + x0250(pix[-5][1]))); - f[3] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[+v][d]) - x0875(pix[0][d]) - x0250(pix[+x][d]))) + fabs(x0875(pix[u][1]) - x1125(pix[-u][1]) + x0250(pix[+w][1])) + fabs(x0875(pix[+w][1]) - x1125(pix[+u][1]) + x0250(pix[+y][1]))); - - float g[5]; - g[0] = (x0875((pix[-u][1] - pix[-u][c])) + x0125((pix[-v][1] - pix[-v][c]))); - g[1] = (x0875((pix[+1][1] - pix[+1][c])) + x0125((pix[+2][1] - pix[+2][c]))); - g[2] = (x0875((pix[-1][1] - pix[-1][c])) + x0125((pix[-2][1] - pix[-2][c]))); - g[3] = (x0875((pix[+u][1] - pix[+u][c])) + x0125((pix[+v][1] - pix[+v][c]))); - - g[4] = (f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / (f[0] + f[1] + f[2] + f[3]); - - const std::array p = { - pix[-u - 1][1] - pix[-u - 1][c], - pix[-u + 0][1] - pix[-u + 0][c], - pix[-u + 1][1] - pix[-u + 1][c], - pix[+0 - 1][1] - pix[+0 - 1][c], - pix[+0 + 0][1] - pix[+0 + 0][c], - pix[+0 + 1][1] - pix[+0 + 1][c], - pix[+u - 1][1] - pix[+u - 1][c], - pix[+u + 0][1] - pix[+u + 0][c], - pix[+u + 1][1] - pix[+u + 1][c] - }; - - const float med = median(p); - - pix[0][c] = LIM(pix[0][1] - (1.30f * g[4] - 0.30f * (pix[0][1] - pix[0][c])), 0.99f * (pix[0][1] - med), 1.01f * (pix[0][1] - med)); - - } - } - - } - - // put modified values to red, green, blue -#ifdef _OPENMP - #pragma omp for -#endif - - for (int i = 0; i < H; i++) { - for (int j = 0; j < W; j++) { - red [i][j] = image[i * W + j][0]; - green[i][j] = image[i * W + j][1]; - blue [i][j] = image[i * W + j][2]; - } - } - } - - free(image); - - t2e.set(); - - if (settings->verbose) { - printf("Refinement Lassus %d usec\n", t2e.etime(t1e)); - } -} - - /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -2505,9 +1518,9 @@ BENCHFUN */ for(int y = 0; y < TILESIZE && y0 + y < H; y++) { for (int j = 0; j < TILESIZE && x0 + j < W; j++) { - red[y0 + y][x0 + j] = tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][0]; - green[y0 + y][x0 + j] = tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][1]; - blue[y0 + y][x0 + j] = tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][2]; + red[y0 + y][x0 + j] = std::max(0.f, tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][0]); + green[y0 + y][x0 + j] = std::max(0.f, tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][1]); + blue[y0 + y][x0 + j] = std::max(0.f, tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][2]); } } diff --git a/rtengine/eahd_demosaic.cc b/rtengine/eahd_demosaic.cc index c470eb297..ad4bda3cd 100644 --- a/rtengine/eahd_demosaic.cc +++ b/rtengine/eahd_demosaic.cc @@ -400,11 +400,11 @@ void RawImageSource::eahd_demosaic () int vc = homv[imx][j]; if (hc > vc) { - green[i - 1][j] = gh[(i - 1) % 4][j]; + green[i - 1][j] = std::max(0.f, gh[(i - 1) % 4][j]); } else if (hc < vc) { - green[i - 1][j] = gv[(i - 1) % 4][j]; + green[i - 1][j] = std::max(0.f, gv[(i - 1) % 4][j]); } else { - green[i - 1][j] = (gh[(i - 1) % 4][j] + gv[(i - 1) % 4][j]) / 2; + green[i - 1][j] = std::max(0.f, (gh[(i - 1) % 4][j] + gv[(i - 1) % 4][j]) / 2); } } } @@ -421,11 +421,11 @@ void RawImageSource::eahd_demosaic () int vc = homv[(i - 1) % 3][j]; if (hc > vc) { - green[i - 1][j] = gh[(i - 1) % 4][j]; + green[i - 1][j] = std::max(0.f, gh[(i - 1) % 4][j]); } else if (hc < vc) { - green[i - 1][j] = gv[(i - 1) % 4][j]; + green[i - 1][j] = std::max(0.f, gv[(i - 1) % 4][j]); } else { - green[i - 1][j] = (gh[(i - 1) % 4][j] + gv[(i - 1) % 4][j]) / 2; + green[i - 1][j] = std::max(0.f, (gh[(i - 1) % 4][j] + gv[(i - 1) % 4][j]) / 2); } } diff --git a/rtengine/fast_demo.cc b/rtengine/fast_demo.cc index aaa5ceb02..772096b87 100644 --- a/rtengine/fast_demo.cc +++ b/rtengine/fast_demo.cc @@ -452,23 +452,23 @@ void RawImageSource::fast_demosaic() #ifdef __SSE2__ for (j = left + 2, cc = 2; j < right - 5; j += 4, cc += 4) { - _mm_storeu_ps(&red[i][j], LVFU(redtile[rr * TS + cc])); - _mm_storeu_ps(&green[i][j], LVFU(greentile[rr * TS + cc])); - _mm_storeu_ps(&blue[i][j], LVFU(bluetile[rr * TS + cc])); + _mm_storeu_ps(&red[i][j], vmaxf(LVFU(redtile[rr * TS + cc]), ZEROV)); + _mm_storeu_ps(&green[i][j], vmaxf(LVFU(greentile[rr * TS + cc]), ZEROV)); + _mm_storeu_ps(&blue[i][j], vmaxf(LVFU(bluetile[rr * TS + cc]), ZEROV)); } for (; j < right - 2; j++, cc++) { - red[i][j] = redtile[rr * TS + cc]; - green[i][j] = greentile[rr * TS + cc]; - blue[i][j] = bluetile[rr * TS + cc]; + red[i][j] = std::max(0.f, redtile[rr * TS + cc]); + green[i][j] = std::max(0.f, greentile[rr * TS + cc]); + blue[i][j] = std::max(0.f, bluetile[rr * TS + cc]); } #else for (int j = left + 2, cc = 2; j < right - 2; j++, cc++) { - red[i][j] = redtile[rr * TS + cc]; - green[i][j] = greentile[rr * TS + cc]; - blue[i][j] = bluetile[rr * TS + cc]; + red[i][j] = std::max(0.f, redtile[rr * TS + cc]); + green[i][j] = std::max(0.f, greentile[rr * TS + cc]); + blue[i][j] = std::max(0.f, bluetile[rr * TS + cc]); } #endif diff --git a/rtengine/hphd_demosaic_RT.cc b/rtengine/hphd_demosaic_RT.cc index 5e05b128e..936c8fa4f 100644 --- a/rtengine/hphd_demosaic_RT.cc +++ b/rtengine/hphd_demosaic_RT.cc @@ -217,7 +217,7 @@ void hphd_green(const RawImage *ri, const array2D &rawData, float** hpmap const float e4 = 1.f / (dx + (std::fabs(d1) + std::fabs(d2)) + (std::fabs(d3) + std::fabs(d4)) * 0.5f); - green[i][j] = rawData[i][j] * 0.5f + (e2 * g2 + e4 * g4) / (e2 + e4); + green[i][j] = std::max(0.f, rawData[i][j] * 0.5f + (e2 * g2 + e4 * g4) / (e2 + e4)); } else if (hpmap[i][j] == 2) { const float g1 = rawData[i - 1][j] - rawData[i - 2][j] * 0.5f; const float g3 = rawData[i + 1][j] - rawData[i + 2][j] * 0.5f; @@ -237,7 +237,7 @@ void hphd_green(const RawImage *ri, const array2D &rawData, float** hpmap const float e3 = 1.f / (dy + (std::fabs(d1) + std::fabs(d2)) + (std::fabs(d3) + std::fabs(d4)) * 0.5f); - green[i][j] = rawData[i][j] * 0.5f + (e1 * g1 + e3 * g3) / (e1 + e3); + green[i][j] = std::max(0.f, rawData[i][j] * 0.5f + (e1 * g1 + e3 * g3) / (e1 + e3)); } else { const float g1 = rawData[i - 1][j] - rawData[i - 2][j] * 0.5f; const float g2 = rawData[i][j + 1] - rawData[i][j + 2] * 0.5f; @@ -275,7 +275,7 @@ void hphd_green(const RawImage *ri, const array2D &rawData, float** hpmap const float e4 = 1.f / (dx + (std::fabs(d1) + std::fabs(d2)) + (std::fabs(d3) + std::fabs(d4)) * 0.5f); - green[i][j] = rawData[i][j] * 0.5f + ((e1 * g1 + e2 * g2) + (e3 * g3 + e4 * g4)) / (e1 + e2 + e3 + e4); + green[i][j] = std::max(0.f, rawData[i][j] * 0.5f + ((e1 * g1 + e2 * g2) + (e3 * g3 + e4 * g4)) / (e1 + e2 + e3 + e4)); } } } diff --git a/rtengine/lmmse_demosaic.cc b/rtengine/lmmse_demosaic.cc new file mode 100644 index 000000000..f4af1b801 --- /dev/null +++ b/rtengine/lmmse_demosaic.cc @@ -0,0 +1,818 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2019 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include + +#include "rawimagesource.h" +#include "rt_math.h" +#include "color.h" +#include "../rtgui/multilangmgr.h" +#include "sleef.h" +#include "opthelper.h" +#include "median.h" + +using namespace std; + +namespace rtengine +{ + +// LSMME demosaicing algorithm +// L. Zhang and X. Wu, +// Color demozaicing via directional Linear Minimum Mean Square-error Estimation, +// IEEE Trans. on Image Processing, vol. 14, pp. 2167-2178, +// Dec. 2005. +// Adapted to RawTherapee by Jacques Desmis 3/2013 +// Improved speed and reduced memory consumption by Ingo Weyrich 2/2015 +// TODO Tiles to reduce memory consumption +void RawImageSource::lmmse_interpolate_omp(int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations) +{ + const int width = winw, height = winh; + const int ba = 10; + const int rr1 = height + 2 * ba; + const int cc1 = width + 2 * ba; + const int w1 = cc1; + const int w2 = 2 * w1; + const int w3 = 3 * w1; + const int w4 = 4 * w1; + float h0, h1, h2, h3, h4, hs; + h0 = 1.0f; + h1 = exp( -1.0f / 8.0f); + h2 = exp( -4.0f / 8.0f); + h3 = exp( -9.0f / 8.0f); + h4 = exp(-16.0f / 8.0f); + hs = h0 + 2.0f * (h1 + h2 + h3 + h4); + h0 /= hs; + h1 /= hs; + h2 /= hs; + h3 /= hs; + h4 /= hs; + int passref = 0; + int iter = 0; + + if (iterations <= 4) { + iter = iterations - 1; + passref = 0; + } else if (iterations <= 6) { + iter = 3; + passref = iterations - 4; + } else if (iterations <= 8) { + iter = 3; + passref = iterations - 6; + } + + bool applyGamma = true; + + if (iterations == 0) { + applyGamma = false; + iter = 0; + } else { + applyGamma = true; + } + + float *rix[5]; + float *qix[5]; + float *buffer = (float *)calloc(static_cast(rr1) * cc1 * 5 * sizeof(float), 1); + + if (buffer == nullptr) { // allocation of big block of memory failed, try to get 5 smaller ones + printf("lmmse_interpolate_omp: allocation of big memory block failed, try to get 5 smaller ones now...\n"); + bool allocationFailed = false; + + for (int i = 0; i < 5; i++) { + qix[i] = (float *)calloc(static_cast(rr1) * cc1 * sizeof(float), 1); + + if (!qix[i]) { // allocation of at least one small block failed + allocationFailed = true; + } + } + + if (allocationFailed) { // fall back to igv_interpolate + printf("lmmse_interpolate_omp: allocation of 5 small memory blocks failed, falling back to igv_interpolate...\n"); + + for (int i = 0; i < 5; i++) { // free the already allocated buffers + if (qix[i]) { + free(qix[i]); + } + } + + igv_interpolate(winw, winh); + return; + } + } else { + qix[0] = buffer; + + for (int i = 1; i < 5; i++) { + qix[i] = qix[i - 1] + rr1 * cc1; + } + } + + if (plistener) { + plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_LMMSE"))); + plistener->setProgress (0.0); + } + + + LUTf *gamtab; + + if (applyGamma) { + gamtab = &(Color::gammatab_24_17a); + } else { + gamtab = new LUTf(65536, LUT_CLIP_BELOW); + gamtab->makeIdentity(65535.f); + } + + +#ifdef _OPENMP + #pragma omp parallel private(rix) +#endif + { +#ifdef _OPENMP + #pragma omp for +#endif + + for (int rrr = ba; rrr < rr1 - ba; rrr++) { + for (int ccc = ba, row = rrr - ba; ccc < cc1 - ba; ccc++) { + int col = ccc - ba; + float *rix = qix[4] + rrr * cc1 + ccc; + rix[0] = (*gamtab)[rawData[row][col]]; + } + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + if (plistener) { + plistener->setProgress (0.1); + } + } + + // G-R(B) +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + + for (int rr = 2; rr < rr1 - 2; rr++) { + // G-R(B) at R(B) location + for (int cc = 2 + (FC(rr, 2) & 1); cc < cc1 - 2; cc += 2) { + rix[4] = qix[4] + rr * cc1 + cc; + float v0 = 0.0625f * (rix[4][-w1 - 1] + rix[4][-w1 + 1] + rix[4][w1 - 1] + rix[4][w1 + 1]) + 0.25f * (rix[4][0]); + // horizontal + rix[0] = qix[0] + rr * cc1 + cc; + rix[0][0] = -0.25f * (rix[4][ -2] + rix[4][ 2]) + xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]); + float Y = v0 + xdiv2f(rix[0][0]); + + if (rix[4][0] > 1.75f * Y) { + rix[0][0] = median(rix[0][0], rix[4][ -1], rix[4][ 1]); + } else { + rix[0][0] = LIM(rix[0][0], 0.0f, 1.0f); + } + + rix[0][0] -= rix[4][0]; + // vertical + rix[1] = qix[1] + rr * cc1 + cc; + rix[1][0] = -0.25f * (rix[4][-w2] + rix[4][w2]) + xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]); + Y = v0 + xdiv2f(rix[1][0]); + + if (rix[4][0] > 1.75f * Y) { + rix[1][0] = median(rix[1][0], rix[4][-w1], rix[4][w1]); + } else { + rix[1][0] = LIM(rix[1][0], 0.0f, 1.0f); + } + + rix[1][0] -= rix[4][0]; + } + + // G-R(B) at G location + for (int ccc = 2 + (FC(rr, 3) & 1); ccc < cc1 - 2; ccc += 2) { + rix[0] = qix[0] + rr * cc1 + ccc; + rix[1] = qix[1] + rr * cc1 + ccc; + rix[4] = qix[4] + rr * cc1 + ccc; + rix[0][0] = 0.25f * (rix[4][ -2] + rix[4][ 2]) - xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]); + rix[1][0] = 0.25f * (rix[4][-w2] + rix[4][w2]) - xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]); + rix[0][0] = LIM(rix[0][0], -1.0f, 0.0f) + rix[4][0]; + rix[1][0] = LIM(rix[1][0], -1.0f, 0.0f) + rix[4][0]; + } + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + if (plistener) { + plistener->setProgress (0.2); + } + } + + + // apply low pass filter on differential colors +#ifdef _OPENMP + #pragma omp for +#endif + + for (int rr = 4; rr < rr1 - 4; rr++) + for (int cc = 4; cc < cc1 - 4; cc++) { + rix[0] = qix[0] + rr * cc1 + cc; + rix[2] = qix[2] + rr * cc1 + cc; + rix[2][0] = h0 * rix[0][0] + h1 * (rix[0][ -1] + rix[0][ 1]) + h2 * (rix[0][ -2] + rix[0][ 2]) + h3 * (rix[0][ -3] + rix[0][ 3]) + h4 * (rix[0][ -4] + rix[0][ 4]); + rix[1] = qix[1] + rr * cc1 + cc; + rix[3] = qix[3] + rr * cc1 + cc; + rix[3][0] = h0 * rix[1][0] + h1 * (rix[1][-w1] + rix[1][w1]) + h2 * (rix[1][-w2] + rix[1][w2]) + h3 * (rix[1][-w3] + rix[1][w3]) + h4 * (rix[1][-w4] + rix[1][w4]); + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + if (plistener) { + plistener->setProgress (0.3); + } + } + + // interpolate G-R(B) at R(B) +#ifdef _OPENMP + #pragma omp for +#endif + + for (int rr = 4; rr < rr1 - 4; rr++) { + int cc = 4 + (FC(rr, 4) & 1); +#ifdef __SSE2__ + vfloat p1v, p2v, p3v, p4v, p5v, p6v, p7v, p8v, p9v, muv, vxv, vnv, xhv, vhv, xvv, vvv; + vfloat epsv = F2V(1e-7); + vfloat ninev = F2V(9.f); + + for (; cc < cc1 - 10; cc += 8) { + rix[0] = qix[0] + rr * cc1 + cc; + rix[1] = qix[1] + rr * cc1 + cc; + rix[2] = qix[2] + rr * cc1 + cc; + rix[3] = qix[3] + rr * cc1 + cc; + rix[4] = qix[4] + rr * cc1 + cc; + // horizontal + p1v = LC2VFU(rix[2][-4]); + p2v = LC2VFU(rix[2][-3]); + p3v = LC2VFU(rix[2][-2]); + p4v = LC2VFU(rix[2][-1]); + p5v = LC2VFU(rix[2][ 0]); + p6v = LC2VFU(rix[2][ 1]); + p7v = LC2VFU(rix[2][ 2]); + p8v = LC2VFU(rix[2][ 3]); + p9v = LC2VFU(rix[2][ 4]); + muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev; + vxv = epsv + SQRV(p1v - muv) + SQRV(p2v - muv) + SQRV(p3v - muv) + SQRV(p4v - muv) + SQRV(p5v - muv) + SQRV(p6v - muv) + SQRV(p7v - muv) + SQRV(p8v - muv) + SQRV(p9v - muv); + p1v -= LC2VFU(rix[0][-4]); + p2v -= LC2VFU(rix[0][-3]); + p3v -= LC2VFU(rix[0][-2]); + p4v -= LC2VFU(rix[0][-1]); + p5v -= LC2VFU(rix[0][ 0]); + p6v -= LC2VFU(rix[0][ 1]); + p7v -= LC2VFU(rix[0][ 2]); + p8v -= LC2VFU(rix[0][ 3]); + p9v -= LC2VFU(rix[0][ 4]); + vnv = epsv + SQRV(p1v) + SQRV(p2v) + SQRV(p3v) + SQRV(p4v) + SQRV(p5v) + SQRV(p6v) + SQRV(p7v) + SQRV(p8v) + SQRV(p9v); + xhv = (LC2VFU(rix[0][0]) * vxv + LC2VFU(rix[2][0]) * vnv) / (vxv + vnv); + vhv = vxv * vnv / (vxv + vnv); + + // vertical + p1v = LC2VFU(rix[3][-w4]); + p2v = LC2VFU(rix[3][-w3]); + p3v = LC2VFU(rix[3][-w2]); + p4v = LC2VFU(rix[3][-w1]); + p5v = LC2VFU(rix[3][ 0]); + p6v = LC2VFU(rix[3][ w1]); + p7v = LC2VFU(rix[3][ w2]); + p8v = LC2VFU(rix[3][ w3]); + p9v = LC2VFU(rix[3][ w4]); + muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev; + vxv = epsv + SQRV(p1v - muv) + SQRV(p2v - muv) + SQRV(p3v - muv) + SQRV(p4v - muv) + SQRV(p5v - muv) + SQRV(p6v - muv) + SQRV(p7v - muv) + SQRV(p8v - muv) + SQRV(p9v - muv); + p1v -= LC2VFU(rix[1][-w4]); + p2v -= LC2VFU(rix[1][-w3]); + p3v -= LC2VFU(rix[1][-w2]); + p4v -= LC2VFU(rix[1][-w1]); + p5v -= LC2VFU(rix[1][ 0]); + p6v -= LC2VFU(rix[1][ w1]); + p7v -= LC2VFU(rix[1][ w2]); + p8v -= LC2VFU(rix[1][ w3]); + p9v -= LC2VFU(rix[1][ w4]); + vnv = epsv + SQRV(p1v) + SQRV(p2v) + SQRV(p3v) + SQRV(p4v) + SQRV(p5v) + SQRV(p6v) + SQRV(p7v) + SQRV(p8v) + SQRV(p9v); + xvv = (LC2VFU(rix[1][0]) * vxv + LC2VFU(rix[3][0]) * vnv) / (vxv + vnv); + vvv = vxv * vnv / (vxv + vnv); + // interpolated G-R(B) + muv = (xhv * vvv + xvv * vhv) / (vhv + vvv); + STC2VFU(rix[4][0], muv); + } + +#endif + + for (; cc < cc1 - 4; cc += 2) { + rix[0] = qix[0] + rr * cc1 + cc; + rix[1] = qix[1] + rr * cc1 + cc; + rix[2] = qix[2] + rr * cc1 + cc; + rix[3] = qix[3] + rr * cc1 + cc; + rix[4] = qix[4] + rr * cc1 + cc; + // horizontal + float p1 = rix[2][-4]; + float p2 = rix[2][-3]; + float p3 = rix[2][-2]; + float p4 = rix[2][-1]; + float p5 = rix[2][ 0]; + float p6 = rix[2][ 1]; + float p7 = rix[2][ 2]; + float p8 = rix[2][ 3]; + float p9 = rix[2][ 4]; + float mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f; + float vx = 1e-7 + SQR(p1 - mu) + SQR(p2 - mu) + SQR(p3 - mu) + SQR(p4 - mu) + SQR(p5 - mu) + SQR(p6 - mu) + SQR(p7 - mu) + SQR(p8 - mu) + SQR(p9 - mu); + p1 -= rix[0][-4]; + p2 -= rix[0][-3]; + p3 -= rix[0][-2]; + p4 -= rix[0][-1]; + p5 -= rix[0][ 0]; + p6 -= rix[0][ 1]; + p7 -= rix[0][ 2]; + p8 -= rix[0][ 3]; + p9 -= rix[0][ 4]; + float vn = 1e-7 + SQR(p1) + SQR(p2) + SQR(p3) + SQR(p4) + SQR(p5) + SQR(p6) + SQR(p7) + SQR(p8) + SQR(p9); + float xh = (rix[0][0] * vx + rix[2][0] * vn) / (vx + vn); + float vh = vx * vn / (vx + vn); + + // vertical + p1 = rix[3][-w4]; + p2 = rix[3][-w3]; + p3 = rix[3][-w2]; + p4 = rix[3][-w1]; + p5 = rix[3][ 0]; + p6 = rix[3][ w1]; + p7 = rix[3][ w2]; + p8 = rix[3][ w3]; + p9 = rix[3][ w4]; + mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f; + vx = 1e-7 + SQR(p1 - mu) + SQR(p2 - mu) + SQR(p3 - mu) + SQR(p4 - mu) + SQR(p5 - mu) + SQR(p6 - mu) + SQR(p7 - mu) + SQR(p8 - mu) + SQR(p9 - mu); + p1 -= rix[1][-w4]; + p2 -= rix[1][-w3]; + p3 -= rix[1][-w2]; + p4 -= rix[1][-w1]; + p5 -= rix[1][ 0]; + p6 -= rix[1][ w1]; + p7 -= rix[1][ w2]; + p8 -= rix[1][ w3]; + p9 -= rix[1][ w4]; + vn = 1e-7 + SQR(p1) + SQR(p2) + SQR(p3) + SQR(p4) + SQR(p5) + SQR(p6) + SQR(p7) + SQR(p8) + SQR(p9); + float xv = (rix[1][0] * vx + rix[3][0] * vn) / (vx + vn); + float vv = vx * vn / (vx + vn); + // interpolated G-R(B) + rix[4][0] = (xh * vv + xv * vh) / (vh + vv); + } + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + if (plistener) { + plistener->setProgress (0.4); + } + } + + // copy CFA values +#ifdef _OPENMP + #pragma omp for +#endif + + for (int rr = 0; rr < rr1; rr++) + for (int cc = 0, row = rr - ba; cc < cc1; cc++) { + int col = cc - ba; + int c = FC(rr, cc); + rix[c] = qix[c] + rr * cc1 + cc; + + if ((row >= 0) & (row < height) & (col >= 0) & (col < width)) { + rix[c][0] = (*gamtab)[rawData[row][col]]; + } else { + rix[c][0] = 0.f; + } + + if (c != 1) { + rix[1] = qix[1] + rr * cc1 + cc; + rix[4] = qix[4] + rr * cc1 + cc; + rix[1][0] = rix[c][0] + rix[4][0]; + } + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + if (plistener) { + plistener->setProgress (0.5); + } + } + + // bilinear interpolation for R/B + // interpolate R/B at G location +#ifdef _OPENMP + #pragma omp for +#endif + + for (int rr = 1; rr < rr1 - 1; rr++) + for (int cc = 1 + (FC(rr, 2) & 1), c = FC(rr, cc + 1); cc < cc1 - 1; cc += 2) { + rix[c] = qix[c] + rr * cc1 + cc; + rix[1] = qix[1] + rr * cc1 + cc; + rix[c][0] = rix[1][0] + xdiv2f(rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1]); + c = 2 - c; + rix[c] = qix[c] + rr * cc1 + cc; + rix[c][0] = rix[1][0] + xdiv2f(rix[c][-w1] - rix[1][-w1] + rix[c][w1] - rix[1][w1]); + c = 2 - c; + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + if (plistener) { + plistener->setProgress (0.6); + } + } + + // interpolate R/B at B/R location +#ifdef _OPENMP + #pragma omp for +#endif + + for (int rr = 1; rr < rr1 - 1; rr++) + for (int cc = 1 + (FC(rr, 1) & 1), c = 2 - FC(rr, cc); cc < cc1 - 1; cc += 2) { + rix[c] = qix[c] + rr * cc1 + cc; + rix[1] = qix[1] + rr * cc1 + cc; + rix[c][0] = rix[1][0] + 0.25f * (rix[c][-w1] - rix[1][-w1] + rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1] + rix[c][ w1] - rix[1][ w1]); + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + if (plistener) { + plistener->setProgress (0.7); + } + } + + }// End of parallelization 1 + + // median filter/ + for (int pass = 0; pass < iter; pass++) { + // Apply 3x3 median filter + // Compute median(R-G) and median(B-G) + +#ifdef _OPENMP + #pragma omp parallel for private(rix) +#endif + + for (int rr = 1; rr < rr1 - 1; rr++) { + for (int c = 0; c < 3; c += 2) { + int d = c + 3 - (c == 0 ? 0 : 1); + int cc = 1; +#ifdef __SSE2__ + + for (; cc < cc1 - 4; cc += 4) { + rix[d] = qix[d] + rr * cc1 + cc; + rix[c] = qix[c] + rr * cc1 + cc; + rix[1] = qix[1] + rr * cc1 + cc; + // Assign 3x3 differential color values + const std::array p = { + LVFU(rix[c][-w1 - 1]) - LVFU(rix[1][-w1 - 1]), + LVFU(rix[c][-w1]) - LVFU(rix[1][-w1]), + LVFU(rix[c][-w1 + 1]) - LVFU(rix[1][-w1 + 1]), + LVFU(rix[c][ -1]) - LVFU(rix[1][ -1]), + LVFU(rix[c][ 0]) - LVFU(rix[1][ 0]), + LVFU(rix[c][ 1]) - LVFU(rix[1][ 1]), + LVFU(rix[c][ w1 - 1]) - LVFU(rix[1][ w1 - 1]), + LVFU(rix[c][ w1]) - LVFU(rix[1][ w1]), + LVFU(rix[c][ w1 + 1]) - LVFU(rix[1][ w1 + 1]) + }; + _mm_storeu_ps(&rix[d][0], median(p)); + } + +#endif + + for (; cc < cc1 - 1; cc++) { + rix[d] = qix[d] + rr * cc1 + cc; + rix[c] = qix[c] + rr * cc1 + cc; + rix[1] = qix[1] + rr * cc1 + cc; + // Assign 3x3 differential color values + const std::array p = { + rix[c][-w1 - 1] - rix[1][-w1 - 1], + rix[c][-w1] - rix[1][-w1], + rix[c][-w1 + 1] - rix[1][-w1 + 1], + rix[c][ -1] - rix[1][ -1], + rix[c][ 0] - rix[1][ 0], + rix[c][ 1] - rix[1][ 1], + rix[c][ w1 - 1] - rix[1][ w1 - 1], + rix[c][ w1] - rix[1][ w1], + rix[c][ w1 + 1] - rix[1][ w1 + 1] + }; + rix[d][0] = median(p); + } + } + } + + // red/blue at GREEN pixel locations & red/blue and green at BLUE/RED pixel locations +#ifdef _OPENMP + #pragma omp parallel for private (rix) +#endif + + for (int rr = 0; rr < rr1; rr++) { + rix[0] = qix[0] + rr * cc1; + rix[1] = qix[1] + rr * cc1; + rix[2] = qix[2] + rr * cc1; + rix[3] = qix[3] + rr * cc1; + rix[4] = qix[4] + rr * cc1; + int c0 = FC(rr, 0); + int c1 = FC(rr, 1); + + if (c0 == 1) { + c1 = 2 - c1; + int d = c1 + 3 - (c1 == 0 ? 0 : 1); + int cc; + + for (cc = 0; cc < cc1 - 1; cc += 2) { + rix[0][0] = rix[1][0] + rix[3][0]; + rix[2][0] = rix[1][0] + rix[4][0]; + rix[0]++; + rix[1]++; + rix[2]++; + rix[3]++; + rix[4]++; + rix[c1][0] = rix[1][0] + rix[d][0]; + rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]); + rix[0]++; + rix[1]++; + rix[2]++; + rix[3]++; + rix[4]++; + } + + if (cc < cc1) { // remaining pixel, only if width is odd + rix[0][0] = rix[1][0] + rix[3][0]; + rix[2][0] = rix[1][0] + rix[4][0]; + } + } else { + c0 = 2 - c0; + int d = c0 + 3 - (c0 == 0 ? 0 : 1); + int cc; + + for (cc = 0; cc < cc1 - 1; cc += 2) { + rix[c0][0] = rix[1][0] + rix[d][0]; + rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]); + rix[0]++; + rix[1]++; + rix[2]++; + rix[3]++; + rix[4]++; + rix[0][0] = rix[1][0] + rix[3][0]; + rix[2][0] = rix[1][0] + rix[4][0]; + rix[0]++; + rix[1]++; + rix[2]++; + rix[3]++; + rix[4]++; + } + + if (cc < cc1) { // remaining pixel, only if width is odd + rix[c0][0] = rix[1][0] + rix[d][0]; + rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]); + } + } + } + } + + if (plistener) { + plistener->setProgress (0.8); + } + + if (applyGamma) { + gamtab = &(Color::igammatab_24_17); + } else { + gamtab->makeIdentity(); + } + + array2D* rgb[3]; + rgb[0] = &red; + rgb[1] = &green; + rgb[2] = &blue; + + // copy result back to image matrix +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int row = 0; row < height; row++) { + for (int col = 0, rr = row + ba; col < width; col++) { + int cc = col + ba; + int c = FC(row, col); + + for (int ii = 0; ii < 3; ii++) + if (ii != c) { + float *rix = qix[ii] + rr * cc1 + cc; + (*(rgb[ii]))[row][col] = std::max(0.f, (*gamtab)[65535.f * rix[0]]); + } else { + (*(rgb[ii]))[row][col] = CLIP(rawData[row][col]); + } + } + } + + if (plistener) { + plistener->setProgress (1.0); + } + + if (buffer) { + free(buffer); + } else + for (int i = 0; i < 5; i++) { + free(qix[i]); + } + + if (!applyGamma) { + delete gamtab; + } + + if (iterations > 4) { + refinement(passref); + } + +} + +void RawImageSource::refinement(int PassCount) +{ + int width = W; + int height = H; + int w1 = width; + int w2 = 2 * w1; + + if (plistener) { + plistener->setProgressStr(M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE")); + } + + array2D *rgb[3]; + rgb[0] = &red; + rgb[1] = &green; + rgb[2] = &blue; + + for (int b = 0; b < PassCount; b++) { + if (plistener) { + plistener->setProgress((float)b / PassCount); + } + + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + float *pix[3]; + + /* Reinforce interpolated green pixels on RED/BLUE pixel locations */ +#ifdef _OPENMP + #pragma omp for +#endif + + for (int row = 2; row < height - 2; row++) { + int col = 2 + (FC(row, 2) & 1); + int c = FC(row, col); +#ifdef __SSE2__ + vfloat dLv, dRv, dUv, dDv, v0v; + vfloat onev = F2V(1.f); + vfloat zd5v = F2V(0.5f); + + for (; col < width - 8; col += 8) { + int indx = row * width + col; + pix[c] = (float*)(*rgb[c]) + indx; + pix[1] = (float*)(*rgb[1]) + indx; + dLv = onev / (onev + vabsf(LC2VFU(pix[c][ -2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1]))); + dRv = onev / (onev + vabsf(LC2VFU(pix[c][ 2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1]))); + dUv = onev / (onev + vabsf(LC2VFU(pix[c][-w2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1]))); + dDv = onev / (onev + vabsf(LC2VFU(pix[c][ w2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1]))); + v0v = vmaxf(ZEROV, LC2VFU(pix[c][0]) + zd5v + ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv)); + STC2VFU(pix[1][0], v0v); + } + +#endif + + for (; col < width - 2; col += 2) { + int indx = row * width + col; + pix[c] = (float*)(*rgb[c]) + indx; + pix[1] = (float*)(*rgb[1]) + indx; + float dL = 1.f / (1.f + fabsf(pix[c][ -2] - pix[c][0]) + fabsf(pix[1][ 1] - pix[1][ -1])); + float dR = 1.f / (1.f + fabsf(pix[c][ 2] - pix[c][0]) + fabsf(pix[1][ 1] - pix[1][ -1])); + float dU = 1.f / (1.f + fabsf(pix[c][-w2] - pix[c][0]) + fabsf(pix[1][w1] - pix[1][-w1])); + float dD = 1.f / (1.f + fabsf(pix[c][ w2] - pix[c][0]) + fabsf(pix[1][w1] - pix[1][-w1])); + float v0 = (pix[c][0] + 0.5f + ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD)); + pix[1][0] = std::max(0.f, v0); + } + } + + /* Reinforce interpolated red/blue pixels on GREEN pixel locations */ +#ifdef _OPENMP + #pragma omp for +#endif + + for (int row = 2; row < height - 2; row++) { + int col = 2 + (FC(row, 3) & 1); + int c = FC(row, col + 1); +#ifdef __SSE2__ + vfloat dLv, dRv, dUv, dDv, v0v; + vfloat onev = F2V(1.f); + vfloat zd5v = F2V(0.5f); + + for (; col < width - 8; col += 8) { + int indx = row * width + col; + pix[1] = (float*)(*rgb[1]) + indx; + + for (int i = 0; i < 2; c = 2 - c, i++) { + pix[c] = (float*)(*rgb[c]) + indx; + dLv = onev / (onev + vabsf(LC2VFU(pix[1][ -2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][ 1]) - LC2VFU(pix[c][ -1]))); + dRv = onev / (onev + vabsf(LC2VFU(pix[1][ 2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][ 1]) - LC2VFU(pix[c][ -1]))); + dUv = onev / (onev + vabsf(LC2VFU(pix[1][-w2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][w1]) - LC2VFU(pix[c][-w1]))); + dDv = onev / (onev + vabsf(LC2VFU(pix[1][ w2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][w1]) - LC2VFU(pix[c][-w1]))); + v0v = vmaxf(ZEROV, LC2VFU(pix[1][0]) + zd5v - ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv)); + STC2VFU(pix[c][0], v0v); + } + } + +#endif + + for (; col < width - 2; col += 2) { + int indx = row * width + col; + pix[1] = (float*)(*rgb[1]) + indx; + + for (int i = 0; i < 2; c = 2 - c, i++) { + pix[c] = (float*)(*rgb[c]) + indx; + float dL = 1.f / (1.f + fabsf(pix[1][ -2] - pix[1][0]) + fabsf(pix[c][ 1] - pix[c][ -1])); + float dR = 1.f / (1.f + fabsf(pix[1][ 2] - pix[1][0]) + fabsf(pix[c][ 1] - pix[c][ -1])); + float dU = 1.f / (1.f + fabsf(pix[1][-w2] - pix[1][0]) + fabsf(pix[c][w1] - pix[c][-w1])); + float dD = 1.f / (1.f + fabsf(pix[1][ w2] - pix[1][0]) + fabsf(pix[c][w1] - pix[c][-w1])); + float v0 = (pix[1][0] + 0.5f - ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD)); + pix[c][0] = std::max(0.f, v0); + } + } + } + + /* Reinforce integrated red/blue pixels on BLUE/RED pixel locations */ +#ifdef _OPENMP + #pragma omp for +#endif + + for (int row = 2; row < height - 2; row++) { + int col = 2 + (FC(row, 2) & 1); + int c = 2 - FC(row, col); +#ifdef __SSE2__ + vfloat dLv, dRv, dUv, dDv, v0v; + vfloat onev = F2V(1.f); + vfloat zd5v = F2V(0.5f); + + for (; col < width - 8; col += 8) { + int indx = row * width + col; + pix[0] = (float*)(*rgb[0]) + indx; + pix[1] = (float*)(*rgb[1]) + indx; + pix[2] = (float*)(*rgb[2]) + indx; + int d = 2 - c; + dLv = onev / (onev + vabsf(LC2VFU(pix[d][ -2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1]))); + dRv = onev / (onev + vabsf(LC2VFU(pix[d][ 2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1]))); + dUv = onev / (onev + vabsf(LC2VFU(pix[d][-w2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1]))); + dDv = onev / (onev + vabsf(LC2VFU(pix[d][ w2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1]))); + v0v = vmaxf(ZEROV, LC2VFU(pix[1][0]) + zd5v - ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv)); + STC2VFU(pix[c][0], v0v); + } + +#endif + + for (; col < width - 2; col += 2) { + int indx = row * width + col; + pix[0] = (float*)(*rgb[0]) + indx; + pix[1] = (float*)(*rgb[1]) + indx; + pix[2] = (float*)(*rgb[2]) + indx; + int d = 2 - c; + float dL = 1.f / (1.f + fabsf(pix[d][ -2] - pix[d][0]) + fabsf(pix[1][ 1] - pix[1][ -1])); + float dR = 1.f / (1.f + fabsf(pix[d][ 2] - pix[d][0]) + fabsf(pix[1][ 1] - pix[1][ -1])); + float dU = 1.f / (1.f + fabsf(pix[d][-w2] - pix[d][0]) + fabsf(pix[1][w1] - pix[1][-w1])); + float dD = 1.f / (1.f + fabsf(pix[d][ w2] - pix[d][0]) + fabsf(pix[1][w1] - pix[1][-w1])); + float v0 = (pix[1][0] + 0.5f - ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD)); + pix[c][0] = std::max(0.f, v0); + } + } + } // end parallel + } +} +#ifdef __SSE2__ +#undef CLIPV +#endif + +} /* namespace */ diff --git a/rtengine/myfile.h b/rtengine/myfile.h index 7c498e556..423edea9a 100644 --- a/rtengine/myfile.h +++ b/rtengine/myfile.h @@ -56,28 +56,26 @@ IMFILE* fopen (const char* fname); IMFILE* gfopen (const char* fname); IMFILE* fopen (unsigned* buf, int size); void fclose (IMFILE* f); -inline int ftell (IMFILE* f) +inline long ftell (IMFILE* f) { - return f->pos; } inline int feof (IMFILE* f) { - return f->eof; } -inline void fseek (IMFILE* f, int p, int how) +inline void fseek (IMFILE* f, long p, int how) { - int fpos = f->pos; + ssize_t fpos = f->pos; if (how == SEEK_SET) { f->pos = p; } else if (how == SEEK_CUR) { f->pos += p; } else if (how == SEEK_END) { - if(p <= 0 && -p <= f->size) { + if (p <= 0 && -p <= f->size) { f->pos = f->size + p; } return; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index ea3152918..d00812d88 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2543,12 +2543,10 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R for (int row = winy; row < winy + winh; row ++) { for (int col = winx; col < winx + winw; col++) { - float val = rawData[row][col]; - int c = FC(row, col); // three colors, 0=R, 1=G, 2=B - int c4 = ( c == 1 && !(row & 1) ) ? 3 : c; // four colors, 0=R, 1=G1, 2=B, 3=G2 - val -= cblacksom[c4]; - val *= scale_mul[c4]; - rawData[row][col] = (val); + const int c = FC(row, col); // three colors, 0=R, 1=G, 2=B + const int c4 = ( c == 1 && !(row & 1) ) ? 3 : c; // four colors, 0=R, 1=G1, 2=B, 3=G2 + const float val = max(0.f, rawData[row][col] - cblacksom[c4]) * scale_mul[c4]; + rawData[row][col] = val; tmpchmax[c] = max(tmpchmax[c], val); } } @@ -2575,10 +2573,8 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R for (int row = winy; row < winy + winh; row ++) { for (int col = winx; col < winx + winw; col++) { - float val = rawData[row][col]; - val -= cblacksom[0]; - val *= scale_mul[0]; - rawData[row][col] = (val); + const float val = max(0.f, rawData[row][col] - cblacksom[0]) * scale_mul[0]; + rawData[row][col] = val; tmpchmax = max(tmpchmax, val); } } @@ -2604,12 +2600,9 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R for (int row = winy; row < winy + winh; row ++) { for (int col = winx; col < winx + winw; col++) { - float val = rawData[row][col]; - int c = ri->XTRANSFC(row, col); - val -= cblacksom[c]; - val *= scale_mul[c]; - - rawData[row][col] = (val); + const int c = ri->XTRANSFC(row, col); + const float val = max(0.f, rawData[row][col] - cblacksom[c]) * scale_mul[c]; + rawData[row][col] = val; tmpchmax[c] = max(tmpchmax[c], val); } } @@ -2638,10 +2631,8 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R { for (int col = winx; col < winx + winw; col++) { for (int c = 0; c < 3; c++) { // three colors, 0=R, 1=G, 2=B - float val = rawData[row][3 * col + c]; - val -= cblacksom[c]; - val *= scale_mul[c]; - rawData[row][3 * col + c] = (val); + const float val = max(0.f, rawData[row][3 * col + c] - cblacksom[c]) * scale_mul[c]; + rawData[row][3 * col + c] = val; tmpchmax[c] = max(tmpchmax[c], val); } } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index f7d905357..28cf30010 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -129,7 +129,6 @@ public: void flushRawData () override; void flushRGB () override; void HLRecovery_Global (const procparams::ToneCurveParams &hrp) override; - void refinement_lassus (int PassCount); void refinement(int PassCount); void setBorder(unsigned int rawBorder) override {border = rawBorder;} bool isRGBSourceModified() const override @@ -267,7 +266,7 @@ protected: void hphd_demosaic(); void vng4_demosaic(const array2D &rawData, array2D &red, array2D &green, array2D &blue); void igv_interpolate(int winw, int winh); - void lmmse_interpolate_omp(int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations); + void lmmse_interpolate_omp(int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations); void amaze_demosaic_RT(int winx, int winy, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, size_t chunkSize = 1, bool measure = false);//Emil's code for AMaZE void dual_demosaic_RT(bool isBayer, const procparams::RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast = false); void fast_demosaic();//Emil's code for fast demosaicing diff --git a/rtengine/rawimagesource_i.h b/rtengine/rawimagesource_i.h index 47c6b5bab..9dfc87985 100644 --- a/rtengine/rawimagesource_i.h +++ b/rtengine/rawimagesource_i.h @@ -90,7 +90,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw } b = g_mul * cg[j] + b / std::max(1, n); - ab[jx] = b; + ab[jx] = std::max(0.f, b); } else { // linear R-G interp. horizontally float r; @@ -103,7 +103,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw r = g_mul * cg[j] + (r_mul * rawData[i][j - 1] - g_mul * cg[j - 1] + r_mul * rawData[i][j + 1] - g_mul * cg[j + 1]) / 2; } - ar[jx] = r; + ar[jx] = std::max(0.f, r); // linear B-G interp. vertically float b; @@ -115,7 +115,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw b = g_mul * cg[j] + (b_mul * rawData[i - 1][j] - g_mul * pg[j] + b_mul * rawData[i + 1][j] - g_mul * ng[j]) / 2; } - ab[jx] = b; + ab[jx] = std::max(0.f, b); } } } else if(pg && ng) { @@ -150,7 +150,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw r = g_mul * cg[j] + r / std::max(n, 1); - ar[jx] = r; + ar[jx] = std::max(0.f, r); } else { // linear B-G interp. horizontally float b; @@ -163,7 +163,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw b = g_mul * cg[j] + (b_mul * rawData[i][j - 1] - g_mul * cg[j - 1] + b_mul * rawData[i][j + 1] - g_mul * cg[j + 1]) / 2; } - ab[jx] = b; + ab[jx] = std::max(0.f, b); // linear R-G interp. vertically float r; @@ -175,7 +175,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw r = g_mul * cg[j] + (r_mul * rawData[i - 1][j] - g_mul * pg[j] + r_mul * rawData[i + 1][j] - g_mul * ng[j]) / 2; } - ar[jx] = r; + ar[jx] = std::max(0.f, r); } } } diff --git a/rtengine/rcd_demosaic.cc b/rtengine/rcd_demosaic.cc index 4ceb92b26..5a86aec40 100644 --- a/rtengine/rcd_demosaic.cc +++ b/rtengine/rcd_demosaic.cc @@ -275,9 +275,9 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) for (int row = rowStart + rcdBorder; row < rowEnd - rcdBorder; ++row) { for (int col = colStart + rcdBorder; col < colEnd - rcdBorder; ++col) { int idx = (row - rowStart) * tileSize + col - colStart ; - red[row][col] = CLIP(rgb[0][idx] * 65535.f); - green[row][col] = CLIP(rgb[1][idx] * 65535.f); - blue[row][col] = CLIP(rgb[2][idx] * 65535.f); + red[row][col] = std::max(0.f, rgb[0][idx] * 65535.f); + green[row][col] = std::max(0.f, rgb[1][idx] * 65535.f); + blue[row][col] = std::max(0.f, rgb[2][idx] * 65535.f); } } diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index b02e75461..79a7c3679 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -473,8 +473,18 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H, } } +#ifdef __SSE2__ + // flush denormals to zero for gaussian blur to avoid performance penalty if there are a lot of zero values in the mask + const auto oldMode = _MM_GET_FLUSH_ZERO_MODE(); + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); +#endif + // blur blend mask to smooth transitions gaussianBlur(blend, blend, W, H, 2.0); + +#ifdef __SSE2__ + _MM_SET_FLUSH_ZERO_MODE(oldMode); +#endif } } } diff --git a/rtengine/vng4_demosaic_RT.cc b/rtengine/vng4_demosaic_RT.cc index 47982b6da..ef456af3a 100644 --- a/rtengine/vng4_demosaic_RT.cc +++ b/rtengine/vng4_demosaic_RT.cc @@ -45,12 +45,12 @@ inline void vng4interpolate_row_redblue (const RawImage *ri, const array2D &rawData, array2D firstRow) { vng4interpolate_row_redblue(ri, rawData, red[row - 1], blue[row - 1], green[row - 2], green[row - 1], green[row], row - 1, W); diff --git a/rtengine/xtrans_demosaic.cc b/rtengine/xtrans_demosaic.cc index c1a526535..cb1315ed0 100644 --- a/rtengine/xtrans_demosaic.cc +++ b/rtengine/xtrans_demosaic.cc @@ -939,9 +939,9 @@ void RawImageSource::xtrans_interpolate (const int passes, const bool useCieLab, avg[3]++; } - red[row + top][col + left] = avg[0] / avg[3]; - green[row + top][col + left] = avg[1] / avg[3]; - blue[row + top][col + left] = avg[2] / avg[3]; + red[row + top][col + left] = std::max(0.f, avg[0] / avg[3]); + green[row + top][col + left] = std::max(0.f, avg[1] / avg[3]); + blue[row + top][col + left] = std::max(0.f, avg[2] / avg[3]); } if(plistenerActive && ((++progressCounter) % 32 == 0)) { diff --git a/tools/gimp-plugin/file-formats.h b/tools/gimp-plugin/file-formats.h index ac8c2fa54..1956988d8 100644 --- a/tools/gimp-plugin/file-formats.h +++ b/tools/gimp-plugin/file-formats.h @@ -39,8 +39,8 @@ static const FileFormat file_formats[] = { { N_("Raw Canon"), - "image/x-canon-cr2,image/x-canon-crw", - "cr2,crw", + "image/x-canon-cr2,image/x-canon-cr3,image/x-canon-crw", + "cr2,cr3,crw", NULL, "file-rawtherapee-canon-load",