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",