diff --git a/rtdata/images/Dark/actions/spGamutCheck.png b/rtdata/images/Dark/actions/spGamutCheck.png new file mode 100644 index 000000000..ab812272a Binary files /dev/null and b/rtdata/images/Dark/actions/spGamutCheck.png differ diff --git a/rtdata/images/Dark/actions/unchanged-18.png b/rtdata/images/Dark/actions/unchanged-18.png new file mode 100644 index 000000000..9d08dda26 Binary files /dev/null and b/rtdata/images/Dark/actions/unchanged-18.png differ diff --git a/rtdata/images/Dark/actions/unchanged-22.png b/rtdata/images/Dark/actions/unchanged-22.png new file mode 100644 index 000000000..db03d456a Binary files /dev/null and b/rtdata/images/Dark/actions/unchanged-22.png differ diff --git a/rtdata/images/Light/actions/spGamutCheck.png b/rtdata/images/Light/actions/spGamutCheck.png new file mode 100644 index 000000000..b1ae3e423 Binary files /dev/null and b/rtdata/images/Light/actions/spGamutCheck.png differ diff --git a/rtdata/images/Light/actions/unchanged-18.png b/rtdata/images/Light/actions/unchanged-18.png new file mode 100644 index 000000000..9d08dda26 Binary files /dev/null and b/rtdata/images/Light/actions/unchanged-18.png differ diff --git a/rtdata/images/Light/actions/unchanged-22.png b/rtdata/images/Light/actions/unchanged-22.png new file mode 100644 index 000000000..db03d456a Binary files /dev/null and b/rtdata/images/Light/actions/unchanged-22.png differ diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 2dc71124e..deca1cdd2 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -632,6 +632,7 @@ HISTORY_MSG_403;O - NB - Sensibilité des bords HISTORY_MSG_404;O - NB - Base amplification HISTORY_MSG_405;O - Débruitage - Niveau 4 HISTORY_MSG_406;O - NB - Pixels voisins +HISTORY_MSG_443;Compensation du Point Noir de Sortie HISTORY_NEWSNAPSHOT;Ajouter HISTORY_NEWSNAPSHOT_TOOLTIP;Raccourci: Alt-s HISTORY_SNAPSHOT;Capture @@ -953,6 +954,7 @@ PREFERENCES_MENUGROUPPROFILEOPERATIONS;Opérations sur les profils PREFERENCES_MENUGROUPRANK;Classement PREFERENCES_MENUOPTIONS;Options du menu PREFERENCES_METADATA;Metadonnées +PREFERENCES_MONBPC;Compensation du Point Noir pour la transformation L*a*b*->Moniteur PREFERENCES_MIN;Mini (100x115) PREFERENCES_MULTITAB;Éditeurs multiple PREFERENCES_MULTITABDUALMON;Éditeurs multiple, si possible sur un second moniteur @@ -1083,6 +1085,8 @@ SAVEDLG_SUBSAMP_3;Meilleure qualité SAVEDLG_TIFFUNCOMPRESSED;TIFF non compressé SAVEDLG_WARNFILENAME;Le fichier sera nommé SHCSELECTOR_TOOLTIP;Cliquez le bouton droit de la souris\npour réinitialiser la position de ces 3 curseurs +SOFTPROOF_GAMUTCHECK_TOOLTIP;Si activé, indique en gris les pixels dont la couleurs est en dehors du gamut du profile de sortie +SOFTPROOF_TOOLTIP;Épreuvage écran\nSi activé, simule le rendu généré par le profiles de sortie de l'outil ICM. Particulièrement utile pour simuler le rendu en sortie d'imprimante. THRESHOLDSELECTOR_B;Bas THRESHOLDSELECTOR_BL;Bas-gauche THRESHOLDSELECTOR_BR;Bas-droite @@ -1456,6 +1460,8 @@ TP_ICM_APPLYLOOKTABLE;Table de recherche TP_ICM_APPLYLOOKTABLE_TOOLTIP;Utilise la table de recherche (LUT) contenu dans le profil DCP. Ce réglage n'est possible que si le profil DCP sélectionné en contient une. TP_ICM_BLENDCMSMATRIX;Mélange des hautes lumières\ndu profil ICC avec la matrice TP_ICM_BLENDCMSMATRIX_TOOLTIP;Activer la récupération des zones brûlées lorsque les profils ICC basés sur la LUT sont utilisés +TP_ICM_BPC;Compensation du Point Noir +TP_ICM_BPC_TOOLTIP;Activez ceci pour faire correspondre le canal Luminosité à l'espace couleur de sortie avec un Point Blanc fixe TP_ICM_DCPILLUMINANT;Illuminant TP_ICM_DCPILLUMINANT_INTERPOLATED;Interpolé TP_ICM_DCPILLUMINANT_TOOLTIP;Sélectionne quel illuminant DCP inclus utiliser. La valeur par défaut est "Interpolé", qui est un mix entre les 2 profils inclus basé sur la Balance des Blancs choisie. Ce paramètre n'est actif que si un fichier DCP Bi-Illuminant avec support de l'interpolation est choisi. diff --git a/rtdata/languages/default b/rtdata/languages/default index ddf2864c5..605c2ea63 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -674,6 +674,7 @@ HISTORY_MSG_439;Retinex - Process HISTORY_MSG_440;CbDL - Method HISTORY_MSG_441;Retinex - Gain transmission HISTORY_MSG_442;Retinex - Scale +HISTORY_MSG_443;Output Black Point Compensation HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1000,6 +1001,7 @@ PREFERENCES_MENUGROUPRANK;Group "Rank" PREFERENCES_MENUOPTIONS;Context Menu Options PREFERENCES_METADATA;Metadata PREFERENCES_MIN;Mini (100x115) +PREFERENCES_MONBPC;Black Point Compensation for the L*a*b*->Monitor transform PREFERENCES_MONINTENT;Default monitor intent PREFERENCES_MONPROFILE;Default monitor profile PREFERENCES_MULTITAB;Multiple Editor Tabs Mode @@ -1136,6 +1138,8 @@ SAVEDLG_SUBSAMP_TOOLTIP;Best compression:\nJ:a:b 4:2:0\nh/v 2/2\nChroma halved h SAVEDLG_TIFFUNCOMPRESSED;Uncompressed TIFF SAVEDLG_WARNFILENAME;File will be named SHCSELECTOR_TOOLTIP;Click right mouse button to reset the position of those 3 sliders. +SOFTPROOF_GAMUTCHECK_TOOLTIP;If active, indicates in grey the pixels which have out of gamut colors from the output profile. +SOFTPROOF_TOOLTIP;Soft-proofing\nIf active, let you simulate de rendering generated by the output profile of the ICM tool. Most useful for simulating printing outputs. THRESHOLDSELECTOR_B;Bottom THRESHOLDSELECTOR_BL;Bottom-left THRESHOLDSELECTOR_BR;Bottom-right @@ -1523,6 +1527,8 @@ TP_ICM_APPLYLOOKTABLE;Look table TP_ICM_APPLYLOOKTABLE_TOOLTIP;Employ the embedded DCP look table. The setting is only enabled if the selected DCP has one. TP_ICM_BLENDCMSMATRIX;Blend ICC highlights with matrix TP_ICM_BLENDCMSMATRIX_TOOLTIP;Enable to recover clipped highlights when using LUT-based ICC profiles. +TP_ICM_BPC;Black Point Compensation +TP_ICM_BPC_TOOLTIP;Enable this to fit the Luminosity channel to the output color space with a fix White Point TP_ICM_DCPILLUMINANT;Illuminant TP_ICM_DCPILLUMINANT_INTERPOLATED;Interpolated TP_ICM_DCPILLUMINANT_TOOLTIP;Select which embedded DCP illuminant to employ. Default is "interpolated" which is a mix between the two based on white balance. The setting is only enabled if a Dual-Illuminant DCP with interpolation support is selected. diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index 64bb19113..7c28801ae 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -156,11 +156,9 @@ void RawImageSource::CA_correct_RT(const double cared, const double cablue, cons const int vblsz = ceil((float)(height + border2) / (ts - border2) + 2 + vz1); const int hblsz = ceil((float)(width + border2) / (ts - border2) + 2 + hz1); - char *buffer1 = (char *) calloc(vblsz * hblsz * (2 * 2 + 1), sizeof(float)); - //block CA shift values and weight assigned to block - float *blockwt = (float*)buffer1; - float (*blockshifts)[2][2] = (float (*)[2][2])(buffer1 + (vblsz * hblsz * sizeof(float))); + float* const blockwt = static_cast(calloc(vblsz * hblsz * (2 * 2 + 1), sizeof(float))); + float (*blockshifts)[2][2] = (float (*)[2][2])(blockwt + vblsz * hblsz); double fitparams[2][2][16]; @@ -1013,7 +1011,7 @@ void RawImageSource::CA_correct_RT(const double cared, const double cablue, cons } free(Gtmp); - free(buffer1); + free(blockwt); free(RawDataTmp); if(plistener) { diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 21abe733c..c80d5e092 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -17,20 +17,20 @@ calculates A x where x is some vector. Stops when rms residual < RMSResidual or Stops at n iterates if MaximumIterates = 0 since that many iterates gives exact solution. Applicable to symmetric positive definite problems only, which is what unconstrained smooth optimization pretty much always is. Parameter pass can be passed through, containing whatever info you like it to contain (matrix info?). -Takes less memory with OkToModify_b = true, and Preconditioner = NULL. */ +Takes less memory with OkToModify_b = true, and Preconditioner = nullptr. */ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b, float *x, float RMSResidual, void *Pass, int MaximumIterates, void Preconditioner(float *Product, float *x, void *Pass)) { int iterate, i; - char* buffer = (char*)malloc(2 * n * sizeof(float) + 128); - float *r = (float*)(buffer + 64); + float* buffer = (float*)malloc(2 * n * sizeof(float) + 128); + float *r = (buffer + 16); //Start r and x. if(x == nullptr) { x = new float[n]; - memset(x, 0, sizeof(float)*n); //Zero initial guess if x == NULL. + memset(x, 0, sizeof(float)*n); //Zero initial guess if x == nullptr. memcpy(r, b, sizeof(float)*n); } else { Ax(r, x, Pass); @@ -61,7 +61,7 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl } //Search direction d. - float *d = (float*)(buffer + n * sizeof(float) + 128); + float *d = (buffer + n + 32); memcpy(d, s, sizeof(float)*n); @@ -127,15 +127,13 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl #endif { float c = 0.0f; - float t; - float temp; #ifdef _OPENMP #pragma omp for reduction(+:rs) // Summation with error correction #endif for(int ii = 0; ii < n; ii++) { - temp = r[ii] * s[ii]; - t = rs + temp; + float temp = r[ii] * s[ii]; + float t = rs + temp; if( fabsf(rs) >= fabsf(temp) ) { c += ((rs - t) + temp); @@ -183,7 +181,7 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl return x; } -MultiDiagonalSymmetricMatrix::MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle) +MultiDiagonalSymmetricMatrix::MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle) : buffer(nullptr), DiagBuffer(nullptr) { n = Dimension; m = NumberOfDiagonalsInLowerTriangle; @@ -223,7 +221,7 @@ bool MultiDiagonalSymmetricMatrix::CreateDiagonal(int index, int StartRow) { DiagBuffer = nullptr; } else { - DiagBuffer = (char*)( ( uintptr_t(buffer) + uintptr_t(63)) / 64 * 64); + DiagBuffer = (float*)( ( uintptr_t(buffer) + uintptr_t(63)) / 64 * 64); } } @@ -239,7 +237,7 @@ bool MultiDiagonalSymmetricMatrix::CreateDiagonal(int index, int StartRow) } if(DiagBuffer != nullptr) { - Diagonals[index] = (float*)(DiagBuffer + (index * (n + padding) * sizeof(float)) + ((index + 16) * 64)); + Diagonals[index] = (DiagBuffer + (index * (n + padding)) + ((index + 16) * 16)); } else { Diagonals[index] = new float[DiagonalLength(StartRow)]; @@ -305,9 +303,9 @@ SSEFUNCTION void MultiDiagonalSymmetricMatrix::VectorProduct(float* RESTRICT Pro const int chunkSize = (lm - srm) / (omp_get_num_procs() * 32); #else const int chunkSize = (lm - srm) / (omp_get_num_procs() * 8); -#endif #endif #pragma omp parallel +#endif { // First fill the big part in the middle // This can be done without intermediate stores to memory and it can be parallelized too @@ -443,8 +441,8 @@ bool MultiDiagonalSymmetricMatrix::CreateIncompleteCholeskyFactorization(int Max } //It's all initialized? Uhkay. Do the actual math then. - int sss, ss, s; - int k, MaxStartRow = StartRows[m - 1]; //Handy number. + int sss, ss; + int MaxStartRow = StartRows[m - 1]; //Handy number. float **l = ic->Diagonals; float *d = ic->Diagonals[0]; //Describes D in LDLt. int icm = ic->m; @@ -506,8 +504,8 @@ bool MultiDiagonalSymmetricMatrix::CreateIncompleteCholeskyFactorization(int Max //This is a loop over k from 1 to j, inclusive. We'll cover that by looping over the index of the diagonals (s), and get k from it. //The first diagonal is d (k = 0), so skip that and have s start at 1. Cover all available s but stop if k exceeds j. - s = 1; - k = icStartRows[s]; + int s = 1; + int k = icStartRows[s]; while(k <= j) { d[j] -= l[s][j - k] * l[s][j - k] * d[j - k]; @@ -554,7 +552,7 @@ bool MultiDiagonalSymmetricMatrix::CreateIncompleteCholeskyFactorization(int Max return true; } -void MultiDiagonalSymmetricMatrix::KillIncompleteCholeskyFactorization() +void MultiDiagonalSymmetricMatrix::KillIncompleteCholeskyFactorization(void) { delete IncompleteCholeskyFactorization; } @@ -713,9 +711,7 @@ SSEFUNCTION float *EdgePreservingDecomposition::CreateBlur(float *Source, float a = Blur, g = Source; } - int i; int w1 = w - 1, h1 = h - 1; -// float eps = 0.02f; const float sqreps = 0.0004f; // removed eps*eps from inner loop diff --git a/rtengine/EdgePreservingDecomposition.h b/rtengine/EdgePreservingDecomposition.h index 944e0ec7f..bf567f103 100644 --- a/rtengine/EdgePreservingDecomposition.h +++ b/rtengine/EdgePreservingDecomposition.h @@ -93,7 +93,7 @@ public: */ float **Diagonals; char *buffer; - char *DiagBuffer; + float *DiagBuffer; int *StartRows; bool CreateDiagonal(int index, int StartRow); int n, m; //The matrix is n x n, with m diagonals on the lower triangle. Don't change these. They should be private but aren't for convenience. diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index c74e49218..6bb0c4c3c 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -37,6 +37,7 @@ #include "opthelper.h" #include "cplx_wavelet_dec.h" #include "median.h" +#include "iccstore.h" #ifdef _OPENMP #include #endif diff --git a/rtengine/LUT.h b/rtengine/LUT.h index 2d3d91ed5..d83a431ca 100644 --- a/rtengine/LUT.h +++ b/rtengine/LUT.h @@ -536,6 +536,8 @@ public: size = 0; upperBound = 0; maxs = 0; + maxsf = 0.f; + clip = 0; } // create an identity LUT (LUT(x) = x) or a scaled identity LUT (LUT(x) = x / divisor) diff --git a/rtengine/array2D.h b/rtengine/array2D.h index d9cfb23e2..2d38d2e15 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -74,7 +74,8 @@ class array2D : { private: - int x, y, owner, flags; + int x, y, owner; + unsigned int flags; T ** ptr; T * data; bool lock; // useful lock to ensure data is not changed anymore. @@ -82,19 +83,19 @@ private: { if ((ptr) && ((h > y) || (4 * h < y))) { delete[] ptr; - ptr = nullptr; + ptr = NULL; } if ((data) && (((h * w) > (x * y)) || ((h * w) < ((x * y) / 4)))) { delete[] data; - data = nullptr; + data = NULL; } - if (ptr == nullptr) { + if (ptr == NULL) { ptr = new T*[h]; } - if (data == nullptr) { + if (data == NULL) { data = new T[h * w + offset]; } @@ -112,7 +113,7 @@ public: // use as empty declaration, resize before use! // very useful as a member object array2D() : - x(0), y(0), owner(0), ptr(nullptr), data(nullptr), lock(0) + x(0), y(0), owner(0), ptr(NULL), data(NULL), lock(0), flags(0) { //printf("got empty array2D init\n"); } @@ -150,7 +151,7 @@ public: if (owner) { data = new T[h * w]; } else { - data = nullptr; + data = NULL; } x = w; @@ -285,6 +286,8 @@ public: if (this != &rhs) { + flags = rhs.flags; + lock = rhs.lock; if (!owner) { // we can only copy same size data if ((x != rhs.x) || (y != rhs.y)) { printf(" assignment error in array2D\n"); diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index 91d4e6c8b..5a155e051 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -558,10 +558,20 @@ CameraConstantsStore::parse_camera_constants_file(Glib::ustring filename_) while ((ret = fread(&buf[datasize], 1, bufsize - datasize, stream)) != 0) { datasize += ret; - if (datasize == bufsize) { + if (datasize == bufsize) { // we need more memory bufsize += increment; - buf = (char *)realloc(buf, bufsize); - increment *= 2; + void *temp = realloc(buf, bufsize); // try to realloc buffer with new size + if(!temp) { // realloc failed + temp = malloc(bufsize); // alloc now buffer + if (temp) { // alloc worked + memcpy(temp, buf, bufsize - increment); // copy old buffer content to new buffer + free(buf); // free old buffer + } else { // alloc didn't work, break + break; + } + } + buf = (char *)temp; // assign new buffer + increment *= 2; // double increment } } diff --git a/rtengine/cfa_linedn_RT.cc b/rtengine/cfa_linedn_RT.cc index 78da79bb5..21fcfb1e5 100644 --- a/rtengine/cfa_linedn_RT.cc +++ b/rtengine/cfa_linedn_RT.cc @@ -68,11 +68,10 @@ void RawImageSource::CLASS cfa_linedn(float noise) { // allocate memory and assure the arrays don't have same 64 byte boundary to avoid L1 conflict misses - char *buffer = (char*)malloc(4 * TS * TS * sizeof(float) + 3 * 64); - float *cfain = (float*)(buffer); - float *cfablur = (float*)(buffer + (TS * TS * sizeof(float)) + 1 * 64); - float *cfadiff = (float*)(buffer + (2 * TS * TS * sizeof(float)) + 2 * 64); - float *cfadn = (float*)(buffer + (3 * TS * TS * sizeof(float)) + 3 * 64); + float *cfain = (float*)malloc(4 * TS * TS * sizeof(float) + 3 * 16 * sizeof(float)); + float *cfablur = (cfain + (TS * TS) + 1 * 16); + float *cfadiff = (cfain + (2 * TS * TS) + 2 * 16); + float *cfadn = (cfain + (3 * TS * TS) + 3 * 16); float linehvar[4], linevvar[4], noisefactor[4][8][2], coeffsq; @@ -250,7 +249,7 @@ void RawImageSource::CLASS cfa_linedn(float noise) } // clean up - free(buffer); + free(cfain); // copy temporary buffer back to image matrix #pragma omp for diff --git a/rtengine/color.cc b/rtengine/color.cc index aa7232db6..5cf1d45b1 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -23,6 +23,7 @@ #include "mytime.h" #include "sleef.c" #include "opthelper.h" +#include "iccstore.h" #define pow_F(a,b) (xexpf(b*xlogf(a))) @@ -542,7 +543,7 @@ void Color::rgb2hsl(float r, float g, float b, float &h, float &s, float &l) h_ = 4. + (var_R - var_G) / C; } - h = float(h_ /= 6.0); + h = float(h_ / 6.0); if ( h < 0.f ) { h += 1.f; @@ -923,7 +924,7 @@ void Color::hsv2rgb (float h, float s, float v, int &r, int &g, int &b) r1 = t; g1 = p; b1 = v; - } else if (i == 5) { + } else /*if (i == 5)*/ { r1 = v; g1 = p; b1 = q; @@ -1647,7 +1648,7 @@ void Color::interpolateRGBColor (float realL, float iplow, float iphigh, int alg Color::xyz2rgb(X, Y, Z, ro, go, bo, rgb_xyz);// ro go bo in gamut } -void Color::calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4, double &gamma5) +void Color::calcGamma (double pwr, double ts, int mode, int imax, GammaValues &gamma) { //from Dcraw (D.Coffin) int i; @@ -1683,12 +1684,13 @@ void Color::calcGamma (double pwr, double ts, int mode, int imax, double &gamma0 } if (!mode--) { - gamma0 = g[0]; - gamma1 = g[1]; - gamma2 = g[2]; - gamma3 = g[3]; - gamma4 = g[4]; - gamma5 = g[5]; + gamma[0] = g[0]; + gamma[1] = g[1]; + gamma[2] = g[2]; + gamma[3] = g[3]; + gamma[4] = g[4]; + gamma[5] = g[5]; + gamma[6] = 0.; return; } } @@ -1996,7 +1998,6 @@ void Color::skinred ( double J, double h, double sres, double Sp, float dred, fl float factorskin, factorsat, factor, factorskinext, interm; float scale = 100.0f / 100.1f; //reduction in normal zone float scaleext = 1.0f; //reduction in transition zone - float protect_redh; float deltaHH = 0.3f; //HH value transition : I have choice 0.3 radians float HH; bool doskin = false; @@ -2077,7 +2078,6 @@ void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, f if(doskin) { float factorskin, factorsat, factor, factorskinext; - float protect_redh; float deltaHH = 0.3f; //HH value transition : I have choice 0.3 radians float chromapro = sres / Sp; @@ -2757,8 +2757,8 @@ SSEFUNCTION void Color::LabGamutMunsell(float *labL, float *laba, float *labb, printf(" Gamut : G1negat=%iiter G165535=%iiter \n", negat, moreRGB); if (MunsDebugInfo) { - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); - printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhuelum[0] , MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%u\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%u\n", MunsDebugInfo->maxdhuelum[0] , MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); } else { printf(" Munsell correction wasn't requested\n"); } diff --git a/rtengine/color.h b/rtengine/color.h index 508efeb31..e2b32e834 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -23,7 +23,6 @@ #include "rt_math.h" #include "LUT.h" #include "labimage.h" -#include "iccstore.h" #include "iccmatrices.h" #include "sleef.c" #define SAT(a,b,c) ((float)max(a,b,c)-(float)min(a,b,c))/(float)max(a,b,c) @@ -31,6 +30,8 @@ namespace rtengine { +typedef std::array GammaValues; + #ifdef _DEBUG class MunsellDebugInfo @@ -47,6 +48,7 @@ public: #endif + class Color { @@ -880,21 +882,21 @@ public: return h; } - /** * @brief Get the gamma curves' parameters used by LCMS2 * @param pwr gamma value [>1] * @param ts slope [0 ; 20] * @param mode [always 0] * @imax imax [always 0] - * @param gamma0 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) - * @param gamma1 used in ip2Lab2rgb [0 ; 20], can be superior to 20, but it's quite unusual(return value) - * @param gamma2 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) - * @param gamma3 used in ip2Lab2rgb [0 ; 1], usually near 0.003(return value) - * @param gamma4 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) - * @param gamma5 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) + * @param gamma a pointer to an array of 6 double gamma values: + * gamma0 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) + * gamma1 used in ip2Lab2rgb [0 ; 20], can be superior to 20, but it's quite unusual(return value) + * gamma2 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) + * gamma3 used in ip2Lab2rgb [0 ; 1], usually near 0.003(return value) + * gamma4 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) + * gamma5 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) */ - static void calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4, double &gamma5); + static void calcGamma (double pwr, double ts, int mode, int imax, GammaValues &gamma); /** diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 2cd56dbb9..cf2fd0d04 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -36,6 +36,7 @@ #include "opthelper.h" #include "ciecam02.h" #include "color.h" +#include "iccstore.h" #undef CLIPD #define CLIPD(a) ((a)>0.0f?((a)<1.0f?(a):1.0f):0.0f) @@ -44,7 +45,7 @@ using namespace std; namespace rtengine { -Curve::Curve () : N(0), x(nullptr), y(nullptr), ypp(nullptr), hashSize(1000 /* has to be initialized to the maximum value */) {} +Curve::Curve () : N(0), ppn(0), x(nullptr), y(nullptr), mc(0.0), mfc(0.0), msc(0.0), mhc(0.0), ypp(nullptr), x1(0.0), y1(0.0), x2(0.0), y2(0.0), x3(0.0), y3(0.0), firstPointIncluded(false), increment(0.0), nbr_points(0), hashSize(1000 /* has to be initialized to the maximum value */) {} void Curve::AddPolygons () { @@ -1434,11 +1435,9 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], double currY = pCurve->getVal(x) - prevY; if (dY > 0.000001 || dY < -0.000001) { - float r1, g1, b1, r2, g2, b2, ro, go, bo; + float r1, g1, b1, r2, g2, b2; Color::hsv2rgb(float(prevY), satur, lr1, r1, g1, b1); Color::hsv2rgb(float(nextY), satur, lr2, r2, g2, b2); - bool chr = false; - bool lum = true; LUTf dum; float X1, X2, Y1, Y2, Z1, Z2, L1, a_1, b_1, c1, h1; Color::rgbxyz(r2, g2, b2, X2, Y2, Z2, xyz_rgb); diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 3593f2777..54fc09622 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -4132,127 +4132,127 @@ mask_set: } } -void CLASS remove_zeroes() -{ - unsigned row, col, tot, n, r, c; - - for (row=0; row < height; row++) - for (col=0; col < width; col++) - if (BAYER(row,col) == 0) { - tot = n = 0; - for (r = row-2; r <= row+2; r++) - for (c = col-2; c <= col+2; c++) - if (r < height && c < width && - FC(r,c) == FC(row,col) && BAYER(r,c)) - tot += (n++,BAYER(r,c)); - if (n) BAYER(row,col) = tot/n; - } -} +//void CLASS remove_zeroes() +//{ +// unsigned row, col, tot, n, r, c; +// +// for (row=0; row < height; row++) +// for (col=0; col < width; col++) +// if (BAYER(row,col) == 0) { +// tot = n = 0; +// for (r = row-2; r <= row+2; r++) +// for (c = col-2; c <= col+2; c++) +// if (r < height && c < width && +// FC(r,c) == FC(row,col) && BAYER(r,c)) +// tot += (n++,BAYER(r,c)); +// if (n) BAYER(row,col) = tot/n; +// } +//} /* Seach from the current directory up to the root looking for a ".badpixels" file, and fix those pixels now. */ -void CLASS bad_pixels (const char *cfname) -{ - FILE *fp=0; - char *fname, *cp, line[128]; - int len, time, row, col, r, c, rad, tot, n, fixed=0; +//void CLASS bad_pixels (const char *cfname) +//{ +// FILE *fp=0; +// char *fname, *cp, line[128]; +// int len, time, row, col, r, c, rad, tot, n, fixed=0; +// +// if (!filters) return; +// if (cfname) +// fp = fopen (cfname, "r"); +// else { +// for (len=32 ; ; len *= 2) { +// fname = (char *) malloc (len); +// if (!fname) return; +// if (getcwd (fname, len-16)) break; +// free (fname); +// if (errno != ERANGE) return; +// } +//#if defined(WIN32) || defined(DJGPP) +// if (fname[1] == ':') +// memmove (fname, fname+2, len-2); +// for (cp=fname; *cp; cp++) +// if (*cp == '\\') *cp = '/'; +//#endif +// cp = fname + strlen(fname); +// if (cp[-1] == '/') cp--; +// while (*fname == '/') { +// strcpy (cp, "/.badpixels"); +// if ((fp = fopen (fname, "r"))) break; +// if (cp == fname) break; +// while (*--cp != '/'); +// } +// free (fname); +// } +// if (!fp) return; +// while (fgets (line, 128, fp)) { +// cp = strchr (line, '#'); +// if (cp) *cp = 0; +// if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; +// if ((unsigned) col >= width || (unsigned) row >= height) continue; +// if (time > timestamp) continue; +// for (tot=n=0, rad=1; rad < 3 && n==0; rad++) +// for (r = row-rad; r <= row+rad; r++) +// for (c = col-rad; c <= col+rad; c++) +// if ((unsigned) r < height && (unsigned) c < width && +// (r != row || c != col) && fcol(r,c) == fcol(row,col)) { +// tot += BAYER2(r,c); +// n++; +// } +// BAYER2(row,col) = tot/n; +// if (verbose) { +// if (!fixed++) +// fprintf (stderr,_("Fixed dead pixels at:")); +// fprintf (stderr, " %d,%d", col, row); +// } +// } +// if (fixed) fputc ('\n', stderr); +// fclose (fp); +//} - if (!filters) return; - if (cfname) - fp = fopen (cfname, "r"); - else { - for (len=32 ; ; len *= 2) { - fname = (char *) malloc (len); - if (!fname) return; - if (getcwd (fname, len-16)) break; - free (fname); - if (errno != ERANGE) return; - } -#if defined(WIN32) || defined(DJGPP) - if (fname[1] == ':') - memmove (fname, fname+2, len-2); - for (cp=fname; *cp; cp++) - if (*cp == '\\') *cp = '/'; -#endif - cp = fname + strlen(fname); - if (cp[-1] == '/') cp--; - while (*fname == '/') { - strcpy (cp, "/.badpixels"); - if ((fp = fopen (fname, "r"))) break; - if (cp == fname) break; - while (*--cp != '/'); - } - free (fname); - } - if (!fp) return; - while (fgets (line, 128, fp)) { - cp = strchr (line, '#'); - if (cp) *cp = 0; - if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; - if ((unsigned) col >= width || (unsigned) row >= height) continue; - if (time > timestamp) continue; - for (tot=n=0, rad=1; rad < 3 && n==0; rad++) - for (r = row-rad; r <= row+rad; r++) - for (c = col-rad; c <= col+rad; c++) - if ((unsigned) r < height && (unsigned) c < width && - (r != row || c != col) && fcol(r,c) == fcol(row,col)) { - tot += BAYER2(r,c); - n++; - } - BAYER2(row,col) = tot/n; - if (verbose) { - if (!fixed++) - fprintf (stderr,_("Fixed dead pixels at:")); - fprintf (stderr, " %d,%d", col, row); - } - } - if (fixed) fputc ('\n', stderr); - fclose (fp); -} - -void CLASS subtract (const char *fname) -{ - FILE *fp; - int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; - ushort *pixel; - - if (!(fp = fopen (fname, "rb"))) { - perror (fname); return; - } - if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; - while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { - if (c == '#') comment = 1; - if (c == '\n') comment = 0; - if (comment) continue; - if (isdigit(c)) number = 1; - if (number) { - if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; - else if (isspace(c)) { - number = 0; nd++; - } else error = 1; - } - } - if (error || nd < 3) { - fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); - fclose (fp); return; - } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { - fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); - fclose (fp); return; - } - pixel = (ushort *) calloc (width, sizeof *pixel); - merror (pixel, "subtract()"); - for (row=0; row < height; row++) { - fread (pixel, 2, width, fp); - for (col=0; col < width; col++) - BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); - } - free (pixel); - fclose (fp); - memset (cblack, 0, sizeof cblack); - black = 0; -} +//void CLASS subtract (const char *fname) +//{ +// FILE *fp; +// int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; +// ushort *pixel; +// +// if (!(fp = fopen (fname, "rb"))) { +// perror (fname); return; +// } +// if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; +// while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { +// if (c == '#') comment = 1; +// if (c == '\n') comment = 0; +// if (comment) continue; +// if (isdigit(c)) number = 1; +// if (number) { +// if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; +// else if (isspace(c)) { +// number = 0; nd++; +// } else error = 1; +// } +// } +// if (error || nd < 3) { +// fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); +// fclose (fp); return; +// } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { +// fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); +// fclose (fp); return; +// } +// pixel = (ushort *) calloc (width, sizeof *pixel); +// merror (pixel, "subtract()"); +// for (row=0; row < height; row++) { +// fread (pixel, 2, width, fp); +// for (col=0; col < width; col++) +// BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); +// } +// free (pixel); +// fclose (fp); +// memset (cblack, 0, sizeof cblack); +// black = 0; +//} void CLASS gamma_curve (double pwr, double ts, int mode, int imax) { @@ -4417,94 +4417,94 @@ void CLASS colorcheck() } #endif -void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) -{ - int i; - for (i=0; i < sc; i++) - temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; - for (; i+sc < size; i++) - temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; - for (; i < size; i++) - temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; -} +//void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) +//{ +// int i; +// for (i=0; i < sc; i++) +// temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; +// for (; i+sc < size; i++) +// temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; +// for (; i < size; i++) +// temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; +//} -void CLASS wavelet_denoise() -{ - float *fimg=0, *temp, thold, mul[2], avg, diff; - int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; - ushort *window[4]; - static const float noise[] = - { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; - - if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); - - while (maximum << scale < 0x10000) scale++; - maximum <<= --scale; - black <<= scale; - FORC4 cblack[c] <<= scale; - if ((size = iheight*iwidth) < 0x15550000) - fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); - merror (fimg, "wavelet_denoise()"); - temp = fimg + size*3; - if ((nc = colors) == 3 && filters) nc++; - FORC(nc) { /* denoise R,G1,B,G3 individually */ - for (i=0; i < size; i++) - fimg[i] = 256 * sqrt(image[i][c] << scale); - for (hpass=lev=0; lev < 5; lev++) { - lpass = size*((lev & 1)+1); - for (row=0; row < iheight; row++) { - hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); - for (col=0; col < iwidth; col++) - fimg[lpass + row*iwidth + col] = temp[col] * 0.25; - } - for (col=0; col < iwidth; col++) { - hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); - for (row=0; row < iheight; row++) - fimg[lpass + row*iwidth + col] = temp[row] * 0.25; - } - thold = threshold * noise[lev]; - for (i=0; i < size; i++) { - fimg[hpass+i] -= fimg[lpass+i]; - if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; - else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; - else fimg[hpass+i] = 0; - if (hpass) fimg[i] += fimg[hpass+i]; - } - hpass = lpass; - } - for (i=0; i < size; i++) - image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); - } - if (filters && colors == 3) { /* pull G1 and G3 closer together */ - for (row=0; row < 2; row++) { - mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; - blk[row] = cblack[FC(row,0) | 1]; - } - for (i=0; i < 4; i++) - window[i] = (ushort *) fimg + width*i; - for (wlast=-1, row=1; row < height-1; row++) { - while (wlast < row+1) { - for (wlast++, i=0; i < 4; i++) - window[(i+3) & 3] = window[i]; - for (col = FC(wlast,1) & 1; col < width; col+=2) - window[2][col] = BAYER(wlast,col); - } - thold = threshold/512; - for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { - avg = ( window[0][col-1] + window[0][col+1] + - window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) - * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; - avg = avg < 0 ? 0 : sqrt(avg); - diff = sqrt(BAYER(row,col)) - avg; - if (diff < -thold) diff += thold; - else if (diff > thold) diff -= thold; - else diff = 0; - BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); - } - } - } - free (fimg); -} +//void CLASS wavelet_denoise() +//{ +// float *fimg=0, *temp, thold, mul[2], avg, diff; +// int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; +// ushort *window[4]; +// static const float noise[] = +// { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; +// +// if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); +// +// while (maximum << scale < 0x10000) scale++; +// maximum <<= --scale; +// black <<= scale; +// FORC4 cblack[c] <<= scale; +// if ((size = iheight*iwidth) < 0x15550000) +// fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); +// merror (fimg, "wavelet_denoise()"); +// temp = fimg + size*3; +// if ((nc = colors) == 3 && filters) nc++; +// FORC(nc) { /* denoise R,G1,B,G3 individually */ +// for (i=0; i < size; i++) +// fimg[i] = 256 * sqrt(image[i][c] << scale); +// for (hpass=lev=0; lev < 5; lev++) { +// lpass = size*((lev & 1)+1); +// for (row=0; row < iheight; row++) { +// hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); +// for (col=0; col < iwidth; col++) +// fimg[lpass + row*iwidth + col] = temp[col] * 0.25; +// } +// for (col=0; col < iwidth; col++) { +// hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); +// for (row=0; row < iheight; row++) +// fimg[lpass + row*iwidth + col] = temp[row] * 0.25; +// } +// thold = threshold * noise[lev]; +// for (i=0; i < size; i++) { +// fimg[hpass+i] -= fimg[lpass+i]; +// if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; +// else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; +// else fimg[hpass+i] = 0; +// if (hpass) fimg[i] += fimg[hpass+i]; +// } +// hpass = lpass; +// } +// for (i=0; i < size; i++) +// image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); +// } +// if (filters && colors == 3) { /* pull G1 and G3 closer together */ +// for (row=0; row < 2; row++) { +// mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; +// blk[row] = cblack[FC(row,0) | 1]; +// } +// for (i=0; i < 4; i++) +// window[i] = (ushort *) fimg + width*i; +// for (wlast=-1, row=1; row < height-1; row++) { +// while (wlast < row+1) { +// for (wlast++, i=0; i < 4; i++) +// window[(i+3) & 3] = window[i]; +// for (col = FC(wlast,1) & 1; col < width; col+=2) +// window[2][col] = BAYER(wlast,col); +// } +// thold = threshold/512; +// for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { +// avg = ( window[0][col-1] + window[0][col+1] + +// window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) +// * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; +// avg = avg < 0 ? 0 : sqrt(avg); +// diff = sqrt(BAYER(row,col)) - avg; +// if (diff < -thold) diff += thold; +// else if (diff > thold) diff -= thold; +// else diff = 0; +// BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); +// } +// } +// } +// free (fimg); +//} void CLASS scale_colors() { @@ -4562,7 +4562,7 @@ skip_block: ; if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; dark = black; sat = maximum; - if (threshold) wavelet_denoise(); +// if (threshold) wavelet_denoise(); maximum -= black; for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { if (dmin > pre_mul[c]) @@ -4668,440 +4668,440 @@ void CLASS pre_interpolate() if (half_size) filters = 0; } -void CLASS border_interpolate (int border) -{ - unsigned row, col, y, x, f, c, sum[8]; - - for (row=0; row < height; row++) - for (col=0; col < width; col++) { - if (col==border && row >= border && row < height-border) - col = width-border; - memset (sum, 0, sizeof sum); - for (y=row-1; y != row+2; y++) - for (x=col-1; x != col+2; x++) - if (y < height && x < width) { - f = fcol(y,x); - sum[f] += image[y*width+x][f]; - sum[f+4]++; - } - f = fcol(row,col); - FORCC if (c != f && sum[c+4]) - image[row*width+col][c] = sum[c] / sum[c+4]; - } -} +//void CLASS border_interpolate (int border) +//{ +// unsigned row, col, y, x, f, c, sum[8]; +// +// for (row=0; row < height; row++) +// for (col=0; col < width; col++) { +// if (col==border && row >= border && row < height-border) +// col = width-border; +// memset (sum, 0, sizeof sum); +// for (y=row-1; y != row+2; y++) +// for (x=col-1; x != col+2; x++) +// if (y < height && x < width) { +// f = fcol(y,x); +// sum[f] += image[y*width+x][f]; +// sum[f+4]++; +// } +// f = fcol(row,col); +// FORCC if (c != f && sum[c+4]) +// image[row*width+col][c] = sum[c] / sum[c+4]; +// } +//} /* RT: delete interpolation functions */ -void CLASS cielab (ushort rgb[3], short lab[3]) -{ - int c, i, j, k; - float r, xyz[3]; - static float cbrt[0x10000], xyz_cam[3][4]; +//void CLASS cielab (ushort rgb[3], short lab[3]) +//{ +// int c, i, j, k; +// float r, xyz[3]; +// static float cbrt[0x10000], xyz_cam[3][4]; +// +// if (!rgb) { +// for (i=0; i < 0x10000; i++) { +// r = i / 65535.0; +// cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; +// } +// for (i=0; i < 3; i++) +// for (j=0; j < colors; j++) +// for (xyz_cam[i][j] = k=0; k < 3; k++) +// xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; +// return; +// } +// xyz[0] = xyz[1] = xyz[2] = 0.5; +// FORCC { +// xyz[0] += xyz_cam[0][c] * rgb[c]; +// xyz[1] += xyz_cam[1][c] * rgb[c]; +// xyz[2] += xyz_cam[2][c] * rgb[c]; +// } +// xyz[0] = cbrt[CLIP((int) xyz[0])]; +// xyz[1] = cbrt[CLIP((int) xyz[1])]; +// xyz[2] = cbrt[CLIP((int) xyz[2])]; +// lab[0] = 64 * (116 * xyz[1] - 16); +// lab[1] = 64 * 500 * (xyz[0] - xyz[1]); +// lab[2] = 64 * 200 * (xyz[1] - xyz[2]); +//} +// +//#define TS 512 /* Tile Size */ +//#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] +// +///* +// Frank Markesteijn's algorithm for Fuji X-Trans sensors +// */ +//void CLASS xtrans_interpolate (int passes) +//{ +// int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; +// int val, ndir, pass, hm[8], avg[4], color[3][8]; +// static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, +// patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, +// { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, +// dir[4] = { 1,TS,TS+1,TS-1 }; +// short allhex[3][3][2][8], *hex; +// ushort min, max, sgrow, sgcol; +// ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; +// short (*lab) [TS][3], (*lix)[3]; +// float (*drv)[TS][TS], diff[6], tr; +// char (*homo)[TS][TS], *buffer; +// +// if (verbose) +// fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); +// +// cielab (0,0); +// ndir = 4 << (passes > 1); +// buffer = (char *) malloc (TS*TS*(ndir*11+6)); +// merror (buffer, "xtrans_interpolate()"); +// rgb = (ushort(*)[TS][TS][3]) buffer; +// lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); +// drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); +// homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); +// +///* Map a green hexagon around each non-green pixel and vice versa: */ +// for (row=0; row < 3; row++) +// for (col=0; col < 3; col++) +// for (ng=d=0; d < 10; d+=2) { +// g = fcol(row,col) == 1; +// if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; +// if (ng == 4) { sgrow = row; sgcol = col; } +// if (ng == g+1) FORC(8) { +// v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; +// h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; +// allhex[row][col][0][c^(g*2 & d)] = h + v*width; +// allhex[row][col][1][c^(g*2 & d)] = h + v*TS; +// } +// } +// +///* Set green1 and green3 to the minimum and maximum allowed values: */ +// for (row=2; row < height-2; row++) +// for (min=~(max=0), col=2; col < width-2; col++) { +// if (fcol(row,col) == 1 && (min=~(max=0))) continue; +// pix = image + row*width + col; +// hex = allhex[row % 3][col % 3][0]; +// if (!max) FORC(6) { +// val = pix[hex[c]][1]; +// if (min > val) min = val; +// if (max < val) max = val; +// } +// pix[0][1] = min; +// pix[0][3] = max; +// switch ((row-sgrow) % 3) { +// case 1: if (row < height-3) { row++; col--; } break; +// case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; +// } +// } +// +// for (top=3; top < height-19; top += TS-16) +// for (left=3; left < width-19; left += TS-16) { +// mrow = MIN (top+TS, height-3); +// mcol = MIN (left+TS, width-3); +// for (row=top; row < mrow; row++) +// for (col=left; col < mcol; col++) +// memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); +// FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); +// +///* Interpolate green horizontally, vertically, and along both diagonals: */ +// for (row=top; row < mrow; row++) +// for (col=left; col < mcol; col++) { +// if ((f = fcol(row,col)) == 1) continue; +// pix = image + row*width + col; +// hex = allhex[row % 3][col % 3][0]; +// color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - +// 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); +// color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + +// 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); +// FORC(2) color[1][2+c] = +// 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * +// (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); +// FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = +// LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); +// } +// +// for (pass=0; pass < passes; pass++) { +// if (pass == 1) +// memcpy (rgb+=4, buffer, 4*sizeof *rgb); +// +///* Recalculate green from interpolated values of closer pixels: */ +// if (pass) { +// for (row=top+2; row < mrow-2; row++) +// for (col=left+2; col < mcol-2; col++) { +// if ((f = fcol(row,col)) == 1) continue; +// pix = image + row*width + col; +// hex = allhex[row % 3][col % 3][1]; +// for (d=3; d < 6; d++) { +// rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; +// val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] +// - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; +// rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); +// } +// } +// } +// +///* Interpolate red and blue values for solitary green pixels: */ +// for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) +// for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { +// rix = &rgb[0][row-top][col-left]; +// h = fcol(row,col+1); +// memset (diff, 0, sizeof diff); +// for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { +// for (c=0; c < 2; c++, h^=2) { +// g = 2*rix[0][1] - rix[i< 1) +// diff[d] += SQR (rix[i< 1 && (d & 1)) +// if (diff[d-1] < diff[d]) +// FORC(2) color[c*2][d] = color[c*2][d-1]; +// if (d < 2 || (d & 1)) { +// FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); +// rix += TS*TS; +// } +// } +// } +// +///* Interpolate red for blue pixels and vice versa: */ +// for (row=top+3; row < mrow-3; row++) +// for (col=left+3; col < mcol-3; col++) { +// if ((f = 2-fcol(row,col)) == 1) continue; +// rix = &rgb[0][row-top][col-left]; +// c = (row-sgrow) % 3 ? TS:1; +// h = 3 * (c ^ TS ^ 1); +// for (d=0; d < 4; d++, rix += TS*TS) { +// i = d > 1 || ((d ^ c) & 1) || +// ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < +// 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; +// rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + +// 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); +// } +// } +// +///* Fill in red and blue for 2x2 blocks of green: */ +// for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) +// for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { +// rix = &rgb[0][row-top][col-left]; +// hex = allhex[row % 3][col % 3][1]; +// for (d=0; d < ndir; d+=2, rix += TS*TS) +// if (hex[d] + hex[d+1]) { +// g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; +// for (c=0; c < 4; c+=2) rix[0][c] = +// CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); +// } else { +// g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; +// for (c=0; c < 4; c+=2) rix[0][c] = +// CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); +// } +// } +// } +// rgb = (ushort(*)[TS][TS][3]) buffer; +// mrow -= top; +// mcol -= left; +// +///* Convert to CIELab and differentiate in all directions: */ +// for (d=0; d < ndir; d++) { +// for (row=2; row < mrow-2; row++) +// for (col=2; col < mcol-2; col++) +// cielab (rgb[d][row][col], lab[row][col]); +// for (f=dir[d & 3],row=3; row < mrow-3; row++) +// for (col=3; col < mcol-3; col++) { +// lix = &lab[row][col]; +// g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; +// drv[d][row][col] = SQR(g) +// + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) +// + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); +// } +// } +// +///* Build homogeneity maps from the derivatives: */ +// memset(homo, 0, ndir*TS*TS); +// for (row=4; row < mrow-4; row++) +// for (col=4; col < mcol-4; col++) { +// for (tr=FLT_MAX, d=0; d < ndir; d++) +// if (tr > drv[d][row][col]) +// tr = drv[d][row][col]; +// tr *= 8; +// for (d=0; d < ndir; d++) +// for (v=-1; v <= 1; v++) +// for (h=-1; h <= 1; h++) +// if (drv[d][row+v][col+h] <= tr) +// homo[d][row][col]++; +// } +// +///* Average the most homogenous pixels for the final result: */ +// if (height-top < TS+4) mrow = height-top+2; +// if (width-left < TS+4) mcol = width-left+2; +// for (row = MIN(top,8); row < mrow-8; row++) +// for (col = MIN(left,8); col < mcol-8; col++) { +// for (d=0; d < ndir; d++) +// for (hm[d]=0, v=-2; v <= 2; v++) +// for (h=-2; h <= 2; h++) +// hm[d] += homo[d][row+v][col+h]; +// for (d=0; d < ndir-4; d++) +// if (hm[d] < hm[d+4]) hm[d ] = 0; else +// if (hm[d] > hm[d+4]) hm[d+4] = 0; +// for (max=hm[0],d=1; d < ndir; d++) +// if (max < hm[d]) max = hm[d]; +// max -= max >> 3; +// memset (avg, 0, sizeof avg); +// for (d=0; d < ndir; d++) +// if (hm[d] >= max) { +// FORC3 avg[c] += rgb[d][row][col][c]; +// avg[3]++; +// } +// FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; +// } +// } +// free(buffer); +// border_interpolate(8); +//} +//#undef fcol +// +// +//#undef TS - if (!rgb) { - for (i=0; i < 0x10000; i++) { - r = i / 65535.0; - cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; - } - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (xyz_cam[i][j] = k=0; k < 3; k++) - xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; - return; - } - xyz[0] = xyz[1] = xyz[2] = 0.5; - FORCC { - xyz[0] += xyz_cam[0][c] * rgb[c]; - xyz[1] += xyz_cam[1][c] * rgb[c]; - xyz[2] += xyz_cam[2][c] * rgb[c]; - } - xyz[0] = cbrt[CLIP((int) xyz[0])]; - xyz[1] = cbrt[CLIP((int) xyz[1])]; - xyz[2] = cbrt[CLIP((int) xyz[2])]; - lab[0] = 64 * (116 * xyz[1] - 16); - lab[1] = 64 * 500 * (xyz[0] - xyz[1]); - lab[2] = 64 * 200 * (xyz[1] - xyz[2]); -} - -#define TS 512 /* Tile Size */ -#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] - -/* - Frank Markesteijn's algorithm for Fuji X-Trans sensors - */ -void CLASS xtrans_interpolate (int passes) -{ - int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; - int val, ndir, pass, hm[8], avg[4], color[3][8]; - static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, - patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, - { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, - dir[4] = { 1,TS,TS+1,TS-1 }; - short allhex[3][3][2][8], *hex; - ushort min, max, sgrow, sgcol; - ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; - short (*lab) [TS][3], (*lix)[3]; - float (*drv)[TS][TS], diff[6], tr; - char (*homo)[TS][TS], *buffer; - - if (verbose) - fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); - - cielab (0,0); - ndir = 4 << (passes > 1); - buffer = (char *) malloc (TS*TS*(ndir*11+6)); - merror (buffer, "xtrans_interpolate()"); - rgb = (ushort(*)[TS][TS][3]) buffer; - lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); - drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); - homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); - -/* Map a green hexagon around each non-green pixel and vice versa: */ - for (row=0; row < 3; row++) - for (col=0; col < 3; col++) - for (ng=d=0; d < 10; d+=2) { - g = fcol(row,col) == 1; - if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; - if (ng == 4) { sgrow = row; sgcol = col; } - if (ng == g+1) FORC(8) { - v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; - h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; - allhex[row][col][0][c^(g*2 & d)] = h + v*width; - allhex[row][col][1][c^(g*2 & d)] = h + v*TS; - } - } - -/* Set green1 and green3 to the minimum and maximum allowed values: */ - for (row=2; row < height-2; row++) - for (min=~(max=0), col=2; col < width-2; col++) { - if (fcol(row,col) == 1 && (min=~(max=0))) continue; - pix = image + row*width + col; - hex = allhex[row % 3][col % 3][0]; - if (!max) FORC(6) { - val = pix[hex[c]][1]; - if (min > val) min = val; - if (max < val) max = val; - } - pix[0][1] = min; - pix[0][3] = max; - switch ((row-sgrow) % 3) { - case 1: if (row < height-3) { row++; col--; } break; - case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; - } - } - - for (top=3; top < height-19; top += TS-16) - for (left=3; left < width-19; left += TS-16) { - mrow = MIN (top+TS, height-3); - mcol = MIN (left+TS, width-3); - for (row=top; row < mrow; row++) - for (col=left; col < mcol; col++) - memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); - FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); - -/* Interpolate green horizontally, vertically, and along both diagonals: */ - for (row=top; row < mrow; row++) - for (col=left; col < mcol; col++) { - if ((f = fcol(row,col)) == 1) continue; - pix = image + row*width + col; - hex = allhex[row % 3][col % 3][0]; - color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - - 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); - color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + - 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); - FORC(2) color[1][2+c] = - 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * - (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); - FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = - LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); - } - - for (pass=0; pass < passes; pass++) { - if (pass == 1) - memcpy (rgb+=4, buffer, 4*sizeof *rgb); - -/* Recalculate green from interpolated values of closer pixels: */ - if (pass) { - for (row=top+2; row < mrow-2; row++) - for (col=left+2; col < mcol-2; col++) { - if ((f = fcol(row,col)) == 1) continue; - pix = image + row*width + col; - hex = allhex[row % 3][col % 3][1]; - for (d=3; d < 6; d++) { - rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; - val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] - - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; - rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); - } - } - } - -/* Interpolate red and blue values for solitary green pixels: */ - for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) - for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { - rix = &rgb[0][row-top][col-left]; - h = fcol(row,col+1); - memset (diff, 0, sizeof diff); - for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { - for (c=0; c < 2; c++, h^=2) { - g = 2*rix[0][1] - rix[i< 1) - diff[d] += SQR (rix[i< 1 && (d & 1)) - if (diff[d-1] < diff[d]) - FORC(2) color[c*2][d] = color[c*2][d-1]; - if (d < 2 || (d & 1)) { - FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); - rix += TS*TS; - } - } - } - -/* Interpolate red for blue pixels and vice versa: */ - for (row=top+3; row < mrow-3; row++) - for (col=left+3; col < mcol-3; col++) { - if ((f = 2-fcol(row,col)) == 1) continue; - rix = &rgb[0][row-top][col-left]; - c = (row-sgrow) % 3 ? TS:1; - h = 3 * (c ^ TS ^ 1); - for (d=0; d < 4; d++, rix += TS*TS) { - i = d > 1 || ((d ^ c) & 1) || - ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < - 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; - rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + - 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); - } - } - -/* Fill in red and blue for 2x2 blocks of green: */ - for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) - for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { - rix = &rgb[0][row-top][col-left]; - hex = allhex[row % 3][col % 3][1]; - for (d=0; d < ndir; d+=2, rix += TS*TS) - if (hex[d] + hex[d+1]) { - g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; - for (c=0; c < 4; c+=2) rix[0][c] = - CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); - } else { - g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; - for (c=0; c < 4; c+=2) rix[0][c] = - CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); - } - } - } - rgb = (ushort(*)[TS][TS][3]) buffer; - mrow -= top; - mcol -= left; - -/* Convert to CIELab and differentiate in all directions: */ - for (d=0; d < ndir; d++) { - for (row=2; row < mrow-2; row++) - for (col=2; col < mcol-2; col++) - cielab (rgb[d][row][col], lab[row][col]); - for (f=dir[d & 3],row=3; row < mrow-3; row++) - for (col=3; col < mcol-3; col++) { - lix = &lab[row][col]; - g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; - drv[d][row][col] = SQR(g) - + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) - + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); - } - } - -/* Build homogeneity maps from the derivatives: */ - memset(homo, 0, ndir*TS*TS); - for (row=4; row < mrow-4; row++) - for (col=4; col < mcol-4; col++) { - for (tr=FLT_MAX, d=0; d < ndir; d++) - if (tr > drv[d][row][col]) - tr = drv[d][row][col]; - tr *= 8; - for (d=0; d < ndir; d++) - for (v=-1; v <= 1; v++) - for (h=-1; h <= 1; h++) - if (drv[d][row+v][col+h] <= tr) - homo[d][row][col]++; - } - -/* Average the most homogenous pixels for the final result: */ - if (height-top < TS+4) mrow = height-top+2; - if (width-left < TS+4) mcol = width-left+2; - for (row = MIN(top,8); row < mrow-8; row++) - for (col = MIN(left,8); col < mcol-8; col++) { - for (d=0; d < ndir; d++) - for (hm[d]=0, v=-2; v <= 2; v++) - for (h=-2; h <= 2; h++) - hm[d] += homo[d][row+v][col+h]; - for (d=0; d < ndir-4; d++) - if (hm[d] < hm[d+4]) hm[d ] = 0; else - if (hm[d] > hm[d+4]) hm[d+4] = 0; - for (max=hm[0],d=1; d < ndir; d++) - if (max < hm[d]) max = hm[d]; - max -= max >> 3; - memset (avg, 0, sizeof avg); - for (d=0; d < ndir; d++) - if (hm[d] >= max) { - FORC3 avg[c] += rgb[d][row][col][c]; - avg[3]++; - } - FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; - } - } - free(buffer); - border_interpolate(8); -} -#undef fcol - - -#undef TS - -void CLASS median_filter() -{ - ushort (*pix)[4]; - int pass, c, i, j, k, med[9]; - static const uchar opt[] = /* Optimal 9-element median search */ - { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, - 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; - - for (pass=1; pass <= med_passes; pass++) { - if (verbose) - fprintf (stderr,_("Median filter pass %d...\n"), pass); - for (c=0; c < 3; c+=2) { - for (pix = image; pix < image+width*height; pix++) - pix[0][3] = pix[0][c]; - for (pix = image+width; pix < image+width*(height-1); pix++) { - if ((pix-image+1) % width < 2) continue; - for (k=0, i = -width; i <= width; i += width) - for (j = i-1; j <= i+1; j++) - med[k++] = pix[j][3] - pix[j][1]; - for (i=0; i < sizeof opt; i+=2) - if (med[opt[i]] > med[opt[i+1]]) - SWAP (med[opt[i]] , med[opt[i+1]]); - pix[0][c] = CLIP(med[4] + pix[0][1]); - } - } - } -} - -void CLASS blend_highlights() -{ - int clip=INT_MAX, row, col, c, i, j; - static const float trans[2][4][4] = - { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, - { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; - static const float itrans[2][4][4] = - { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, - { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; - float cam[2][4], lab[2][4], sum[2], chratio; - - if ((unsigned) (colors-3) > 1) return; - if (verbose) fprintf (stderr,_("Blending highlights...\n")); - FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; - for (row=0; row < height; row++) - for (col=0; col < width; col++) { - FORCC if (image[row*width+col][c] > clip) break; - if (c == colors) continue; - FORCC { - cam[0][c] = image[row*width+col][c]; - cam[1][c] = MIN(cam[0][c],clip); - } - for (i=0; i < 2; i++) { - FORCC for (lab[i][c]=j=0; j < colors; j++) - lab[i][c] += trans[colors-3][c][j] * cam[i][j]; - for (sum[i]=0,c=1; c < colors; c++) - sum[i] += SQR(lab[i][c]); - } - chratio = sqrt(sum[1]/sum[0]); - for (c=1; c < colors; c++) - lab[0][c] *= chratio; - FORCC for (cam[0][c]=j=0; j < colors; j++) - cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; - FORCC image[row*width+col][c] = cam[0][c] / colors; - } -} - -#define SCALE (4 >> shrink) -void CLASS recover_highlights() -{ - float *map, sum, wgt, grow; - int hsat[4], count, spread, change, val, i; - unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; - ushort *pixel; - static const signed char dir[8][2] = - { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; - - if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); - - grow = pow (2, 4-highlight); - FORCC hsat[c] = 32000 * pre_mul[c]; - for (kc=0, c=1; c < colors; c++) - if (pre_mul[kc] < pre_mul[c]) kc = c; - high = height / SCALE; - wide = width / SCALE; - map = (float *) calloc (high, wide*sizeof *map); - merror (map, "recover_highlights()"); - FORCC if (c != kc) { - memset (map, 0, high*wide*sizeof *map); - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - sum = wgt = count = 0; - for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) - for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { - pixel = image[row*width+col]; - if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { - sum += pixel[c]; - wgt += pixel[kc]; - count++; - } - } - if (count == SCALE*SCALE) - map[mrow*wide+mcol] = sum / wgt; - } - for (spread = 32/grow; spread--; ) { - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - if (map[mrow*wide+mcol]) continue; - sum = count = 0; - for (d=0; d < 8; d++) { - y = mrow + dir[d][0]; - x = mcol + dir[d][1]; - if (y < high && x < wide && map[y*wide+x] > 0) { - sum += (1 + (d & 1)) * map[y*wide+x]; - count += 1 + (d & 1); - } - } - if (count > 3) - map[mrow*wide+mcol] = - (sum+grow) / (count+grow); - } - for (change=i=0; i < high*wide; i++) - if (map[i] < 0) { - map[i] = -map[i]; - change = 1; - } - if (!change) break; - } - for (i=0; i < high*wide; i++) - if (map[i] == 0) map[i] = 1; - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) - for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { - pixel = image[row*width+col]; - if (pixel[c] / hsat[c] > 1) { - val = pixel[kc] * map[mrow*wide+mcol]; - if (pixel[c] < val) pixel[c] = CLIP(val); - } - } - } - } - free (map); -} -#undef SCALE +//void CLASS median_filter() +//{ +// ushort (*pix)[4]; +// int pass, c, i, j, k, med[9]; +// static const uchar opt[] = /* Optimal 9-element median search */ +// { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, +// 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; +// +// for (pass=1; pass <= med_passes; pass++) { +// if (verbose) +// fprintf (stderr,_("Median filter pass %d...\n"), pass); +// for (c=0; c < 3; c+=2) { +// for (pix = image; pix < image+width*height; pix++) +// pix[0][3] = pix[0][c]; +// for (pix = image+width; pix < image+width*(height-1); pix++) { +// if ((pix-image+1) % width < 2) continue; +// for (k=0, i = -width; i <= width; i += width) +// for (j = i-1; j <= i+1; j++) +// med[k++] = pix[j][3] - pix[j][1]; +// for (i=0; i < sizeof opt; i+=2) +// if (med[opt[i]] > med[opt[i+1]]) +// SWAP (med[opt[i]] , med[opt[i+1]]); +// pix[0][c] = CLIP(med[4] + pix[0][1]); +// } +// } +// } +//} +// +//void CLASS blend_highlights() +//{ +// int clip=INT_MAX, row, col, c, i, j; +// static const float trans[2][4][4] = +// { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, +// { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; +// static const float itrans[2][4][4] = +// { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, +// { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; +// float cam[2][4], lab[2][4], sum[2], chratio; +// +// if ((unsigned) (colors-3) > 1) return; +// if (verbose) fprintf (stderr,_("Blending highlights...\n")); +// FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; +// for (row=0; row < height; row++) +// for (col=0; col < width; col++) { +// FORCC if (image[row*width+col][c] > clip) break; +// if (c == colors) continue; +// FORCC { +// cam[0][c] = image[row*width+col][c]; +// cam[1][c] = MIN(cam[0][c],clip); +// } +// for (i=0; i < 2; i++) { +// FORCC for (lab[i][c]=j=0; j < colors; j++) +// lab[i][c] += trans[colors-3][c][j] * cam[i][j]; +// for (sum[i]=0,c=1; c < colors; c++) +// sum[i] += SQR(lab[i][c]); +// } +// chratio = sqrt(sum[1]/sum[0]); +// for (c=1; c < colors; c++) +// lab[0][c] *= chratio; +// FORCC for (cam[0][c]=j=0; j < colors; j++) +// cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; +// FORCC image[row*width+col][c] = cam[0][c] / colors; +// } +//} +// +//#define SCALE (4 >> shrink) +//void CLASS recover_highlights() +//{ +// float *map, sum, wgt, grow; +// int hsat[4], count, spread, change, val, i; +// unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; +// ushort *pixel; +// static const signed char dir[8][2] = +// { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; +// +// if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); +// +// grow = pow (2, 4-highlight); +// FORCC hsat[c] = 32000 * pre_mul[c]; +// for (kc=0, c=1; c < colors; c++) +// if (pre_mul[kc] < pre_mul[c]) kc = c; +// high = height / SCALE; +// wide = width / SCALE; +// map = (float *) calloc (high, wide*sizeof *map); +// merror (map, "recover_highlights()"); +// FORCC if (c != kc) { +// memset (map, 0, high*wide*sizeof *map); +// for (mrow=0; mrow < high; mrow++) +// for (mcol=0; mcol < wide; mcol++) { +// sum = wgt = count = 0; +// for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) +// for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { +// pixel = image[row*width+col]; +// if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { +// sum += pixel[c]; +// wgt += pixel[kc]; +// count++; +// } +// } +// if (count == SCALE*SCALE) +// map[mrow*wide+mcol] = sum / wgt; +// } +// for (spread = 32/grow; spread--; ) { +// for (mrow=0; mrow < high; mrow++) +// for (mcol=0; mcol < wide; mcol++) { +// if (map[mrow*wide+mcol]) continue; +// sum = count = 0; +// for (d=0; d < 8; d++) { +// y = mrow + dir[d][0]; +// x = mcol + dir[d][1]; +// if (y < high && x < wide && map[y*wide+x] > 0) { +// sum += (1 + (d & 1)) * map[y*wide+x]; +// count += 1 + (d & 1); +// } +// } +// if (count > 3) +// map[mrow*wide+mcol] = - (sum+grow) / (count+grow); +// } +// for (change=i=0; i < high*wide; i++) +// if (map[i] < 0) { +// map[i] = -map[i]; +// change = 1; +// } +// if (!change) break; +// } +// for (i=0; i < high*wide; i++) +// if (map[i] == 0) map[i] = 1; +// for (mrow=0; mrow < high; mrow++) +// for (mcol=0; mcol < wide; mcol++) { +// for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) +// for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { +// pixel = image[row*width+col]; +// if (pixel[c] / hsat[c] > 1) { +// val = pixel[kc] * map[mrow*wide+mcol]; +// if (pixel[c] < val) pixel[c] = CLIP(val); +// } +// } +// } +// } +// free (map); +//} +//#undef SCALE void CLASS tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save) @@ -9533,55 +9533,55 @@ notraw: if (flip == UINT_MAX) flip = 0; } -#ifndef NO_LCMS -void CLASS apply_profile (const char *input, const char *output) -{ - char *prof; - cmsHPROFILE hInProfile=0, hOutProfile=0; - cmsHTRANSFORM hTransform; - FILE *fp; - unsigned size; - - if (strcmp (input, "embed")) - hInProfile = cmsOpenProfileFromFile (input, "r"); - else if (profile_length) { - prof = (char *) malloc (profile_length); - merror (prof, "apply_profile()"); - fseek (ifp, profile_offset, SEEK_SET); - fread (prof, 1, profile_length, ifp); - hInProfile = cmsOpenProfileFromMem (prof, profile_length); - free (prof); - } else - fprintf (stderr,_("%s has no embedded profile.\n"), ifname); - if (!hInProfile) return; - if (!output) - hOutProfile = cmsCreate_sRGBProfile(); - else if ((fp = fopen (output, "rb"))) { - fread (&size, 4, 1, fp); - fseek (fp, 0, SEEK_SET); - oprof = (unsigned *) malloc (size = ntohl(size)); - merror (oprof, "apply_profile()"); - fread (oprof, 1, size, fp); - fclose (fp); - if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { - free (oprof); - oprof = 0; - } - } else - fprintf (stderr,_("Cannot open file %s!\n"), output); - if (!hOutProfile) goto quit; - if (verbose) - fprintf (stderr,_("Applying color profile...\n")); - hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, - hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); - cmsDoTransform (hTransform, image, image, width*height); - raw_color = 1; /* Don't use rgb_cam with a profile */ - cmsDeleteTransform (hTransform); - cmsCloseProfile (hOutProfile); -quit: - cmsCloseProfile (hInProfile); -} -#endif +//#ifndef NO_LCMS +//void CLASS apply_profile (const char *input, const char *output) +//{ +// char *prof; +// cmsHPROFILE hInProfile=0, hOutProfile=0; +// cmsHTRANSFORM hTransform; +// FILE *fp; +// unsigned size; +// +// if (strcmp (input, "embed")) +// hInProfile = cmsOpenProfileFromFile (input, "r"); +// else if (profile_length) { +// prof = (char *) malloc (profile_length); +// merror (prof, "apply_profile()"); +// fseek (ifp, profile_offset, SEEK_SET); +// fread (prof, 1, profile_length, ifp); +// hInProfile = cmsOpenProfileFromMem (prof, profile_length); +// free (prof); +// } else +// fprintf (stderr,_("%s has no embedded profile.\n"), ifname); +// if (!hInProfile) return; +// if (!output) +// hOutProfile = cmsCreate_sRGBProfile(); +// else if ((fp = fopen (output, "rb"))) { +// fread (&size, 4, 1, fp); +// fseek (fp, 0, SEEK_SET); +// oprof = (unsigned *) malloc (size = ntohl(size)); +// merror (oprof, "apply_profile()"); +// fread (oprof, 1, size, fp); +// fclose (fp); +// if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { +// free (oprof); +// oprof = 0; +// } +// } else +// fprintf (stderr,_("Cannot open file %s!\n"), output); +// if (!hOutProfile) goto quit; +// if (verbose) +// fprintf (stderr,_("Applying color profile...\n")); +// hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, +// hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); +// cmsDoTransform (hTransform, image, image, width*height); +// raw_color = 1; /* Don't use rgb_cam with a profile */ +// cmsDeleteTransform (hTransform); +// cmsCloseProfile (hOutProfile); +//quit: +// cmsCloseProfile (hInProfile); +//} +//#endif /* RT: DNG Float */ diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 666b4276f..9d15a5826 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -43,14 +43,14 @@ public: :exif_base(-1) ,ciff_base(-1) ,ciff_len(0) - ,ifp(nullptr),ofp(nullptr) + ,ifp(NULL),ofp(NULL) ,order(0x4949) - ,ifname(nullptr) - ,meta_data(nullptr) + ,ifname(NULL) + ,meta_data(NULL) ,shot_select(0),multi_out(0) - ,float_raw_image(nullptr) - ,image(nullptr) - ,bright(1.),threshold(0.) + ,float_raw_image(NULL) + ,image(NULL) + ,bright(1.) ,half_size(0),four_color_rgb(0),document_mode(0),highlight(0) ,verbose(0) ,use_auto_wb(0),use_camera_wb(0),use_camera_matrix(1) @@ -344,23 +344,23 @@ void foveon_make_curves(short **curvep, float dq[3], float div[3], float filt); int foveon_apply_curve (short *curve, int i); void foveon_interpolate(); -void xtrans_interpolate (int passes); -void cielab (ushort rgb[3], short lab[3]); +//void xtrans_interpolate (int passes); +//void cielab (ushort rgb[3], short lab[3]); -void remove_zeroes(); -void bad_pixels (const char *cfname); -void subtract (const char *fname); +//void remove_zeroes(); +//void bad_pixels (const char *cfname); +//void subtract (const char *fname); void gamma_curve (double pwr, double ts, int mode, int imax); void pseudoinverse (double (*in)[3], double (*out)[3], int size); void cam_xyz_coeff (float rgb_cam[3][4], double cam_xyz[4][3]); -void hat_transform (float *temp, float *base, int st, int size, int sc); -void wavelet_denoise(); +//void hat_transform (float *temp, float *base, int st, int size, int sc); +//void wavelet_denoise(); void scale_colors(); void pre_interpolate(); -void border_interpolate (int border); -void median_filter(); -void blend_highlights(); -void recover_highlights(); +//void border_interpolate (int border); +//void median_filter(); +//void blend_highlights(); +//void recover_highlights(); void crop_masked_pixels(); void tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save); @@ -397,7 +397,6 @@ void simple_coeff (int index); short guess_byte_order (int words); float find_green (int bps, int bite, int off0, int off1); void identify(); -void apply_profile (const char *input, const char *output); void jpeg_thumb() {} // not needed bool dcraw_coeff_overrides(const char make[], const char model[], int iso_speed, short trans[12], int *black_level, int *white_level); void shiftXtransMatrix( const int offsy, const int offsx) { diff --git a/rtengine/dcraw.patch b/rtengine/dcraw.patch index 82f2ec9b8..e23136d68 100644 --- a/rtengine/dcraw.patch +++ b/rtengine/dcraw.patch @@ -1,5 +1,5 @@ ---- dcraw.c 2016-09-30 21:19:28.312191811 +0200 -+++ dcraw.cc 2016-09-30 22:41:28.157442526 +0200 +--- dcraw.c 2016-10-11 13:24:24 +0000 ++++ dcraw.cc 2016-10-17 19:32:24 +0000 @@ -1,3 +1,16 @@ +/*RT*/#include +/*RT*/#include @@ -833,10 +833,468 @@ if (mask[0][3] > 0) goto mask_set; if (load_raw == &CLASS canon_load_raw || load_raw == &CLASS lossless_jpeg_load_raw) { -@@ -4366,239 +4690,8 @@ - } +@@ -3808,127 +4132,127 @@ + } } +-void CLASS remove_zeroes() +-{ +- unsigned row, col, tot, n, r, c; +- +- for (row=0; row < height; row++) +- for (col=0; col < width; col++) +- if (BAYER(row,col) == 0) { +- tot = n = 0; +- for (r = row-2; r <= row+2; r++) +- for (c = col-2; c <= col+2; c++) +- if (r < height && c < width && +- FC(r,c) == FC(row,col) && BAYER(r,c)) +- tot += (n++,BAYER(r,c)); +- if (n) BAYER(row,col) = tot/n; +- } +-} ++//void CLASS remove_zeroes() ++//{ ++// unsigned row, col, tot, n, r, c; ++// ++// for (row=0; row < height; row++) ++// for (col=0; col < width; col++) ++// if (BAYER(row,col) == 0) { ++// tot = n = 0; ++// for (r = row-2; r <= row+2; r++) ++// for (c = col-2; c <= col+2; c++) ++// if (r < height && c < width && ++// FC(r,c) == FC(row,col) && BAYER(r,c)) ++// tot += (n++,BAYER(r,c)); ++// if (n) BAYER(row,col) = tot/n; ++// } ++//} + + /* + Seach from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. + */ +-void CLASS bad_pixels (const char *cfname) +-{ +- FILE *fp=0; +- char *fname, *cp, line[128]; +- int len, time, row, col, r, c, rad, tot, n, fixed=0; +- +- if (!filters) return; +- if (cfname) +- fp = fopen (cfname, "r"); +- else { +- for (len=32 ; ; len *= 2) { +- fname = (char *) malloc (len); +- if (!fname) return; +- if (getcwd (fname, len-16)) break; +- free (fname); +- if (errno != ERANGE) return; +- } +-#if defined(WIN32) || defined(DJGPP) +- if (fname[1] == ':') +- memmove (fname, fname+2, len-2); +- for (cp=fname; *cp; cp++) +- if (*cp == '\\') *cp = '/'; +-#endif +- cp = fname + strlen(fname); +- if (cp[-1] == '/') cp--; +- while (*fname == '/') { +- strcpy (cp, "/.badpixels"); +- if ((fp = fopen (fname, "r"))) break; +- if (cp == fname) break; +- while (*--cp != '/'); +- } +- free (fname); +- } +- if (!fp) return; +- while (fgets (line, 128, fp)) { +- cp = strchr (line, '#'); +- if (cp) *cp = 0; +- if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; +- if ((unsigned) col >= width || (unsigned) row >= height) continue; +- if (time > timestamp) continue; +- for (tot=n=0, rad=1; rad < 3 && n==0; rad++) +- for (r = row-rad; r <= row+rad; r++) +- for (c = col-rad; c <= col+rad; c++) +- if ((unsigned) r < height && (unsigned) c < width && +- (r != row || c != col) && fcol(r,c) == fcol(row,col)) { +- tot += BAYER2(r,c); +- n++; +- } +- BAYER2(row,col) = tot/n; +- if (verbose) { +- if (!fixed++) +- fprintf (stderr,_("Fixed dead pixels at:")); +- fprintf (stderr, " %d,%d", col, row); +- } +- } +- if (fixed) fputc ('\n', stderr); +- fclose (fp); +-} +- +-void CLASS subtract (const char *fname) +-{ +- FILE *fp; +- int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; +- ushort *pixel; +- +- if (!(fp = fopen (fname, "rb"))) { +- perror (fname); return; +- } +- if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; +- while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { +- if (c == '#') comment = 1; +- if (c == '\n') comment = 0; +- if (comment) continue; +- if (isdigit(c)) number = 1; +- if (number) { +- if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; +- else if (isspace(c)) { +- number = 0; nd++; +- } else error = 1; +- } +- } +- if (error || nd < 3) { +- fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); +- fclose (fp); return; +- } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { +- fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); +- fclose (fp); return; +- } +- pixel = (ushort *) calloc (width, sizeof *pixel); +- merror (pixel, "subtract()"); +- for (row=0; row < height; row++) { +- fread (pixel, 2, width, fp); +- for (col=0; col < width; col++) +- BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); +- } +- free (pixel); +- fclose (fp); +- memset (cblack, 0, sizeof cblack); +- black = 0; +-} ++//void CLASS bad_pixels (const char *cfname) ++//{ ++// FILE *fp=0; ++// char *fname, *cp, line[128]; ++// int len, time, row, col, r, c, rad, tot, n, fixed=0; ++// ++// if (!filters) return; ++// if (cfname) ++// fp = fopen (cfname, "r"); ++// else { ++// for (len=32 ; ; len *= 2) { ++// fname = (char *) malloc (len); ++// if (!fname) return; ++// if (getcwd (fname, len-16)) break; ++// free (fname); ++// if (errno != ERANGE) return; ++// } ++//#if defined(WIN32) || defined(DJGPP) ++// if (fname[1] == ':') ++// memmove (fname, fname+2, len-2); ++// for (cp=fname; *cp; cp++) ++// if (*cp == '\\') *cp = '/'; ++//#endif ++// cp = fname + strlen(fname); ++// if (cp[-1] == '/') cp--; ++// while (*fname == '/') { ++// strcpy (cp, "/.badpixels"); ++// if ((fp = fopen (fname, "r"))) break; ++// if (cp == fname) break; ++// while (*--cp != '/'); ++// } ++// free (fname); ++// } ++// if (!fp) return; ++// while (fgets (line, 128, fp)) { ++// cp = strchr (line, '#'); ++// if (cp) *cp = 0; ++// if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; ++// if ((unsigned) col >= width || (unsigned) row >= height) continue; ++// if (time > timestamp) continue; ++// for (tot=n=0, rad=1; rad < 3 && n==0; rad++) ++// for (r = row-rad; r <= row+rad; r++) ++// for (c = col-rad; c <= col+rad; c++) ++// if ((unsigned) r < height && (unsigned) c < width && ++// (r != row || c != col) && fcol(r,c) == fcol(row,col)) { ++// tot += BAYER2(r,c); ++// n++; ++// } ++// BAYER2(row,col) = tot/n; ++// if (verbose) { ++// if (!fixed++) ++// fprintf (stderr,_("Fixed dead pixels at:")); ++// fprintf (stderr, " %d,%d", col, row); ++// } ++// } ++// if (fixed) fputc ('\n', stderr); ++// fclose (fp); ++//} ++ ++//void CLASS subtract (const char *fname) ++//{ ++// FILE *fp; ++// int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; ++// ushort *pixel; ++// ++// if (!(fp = fopen (fname, "rb"))) { ++// perror (fname); return; ++// } ++// if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; ++// while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { ++// if (c == '#') comment = 1; ++// if (c == '\n') comment = 0; ++// if (comment) continue; ++// if (isdigit(c)) number = 1; ++// if (number) { ++// if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; ++// else if (isspace(c)) { ++// number = 0; nd++; ++// } else error = 1; ++// } ++// } ++// if (error || nd < 3) { ++// fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); ++// fclose (fp); return; ++// } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { ++// fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); ++// fclose (fp); return; ++// } ++// pixel = (ushort *) calloc (width, sizeof *pixel); ++// merror (pixel, "subtract()"); ++// for (row=0; row < height; row++) { ++// fread (pixel, 2, width, fp); ++// for (col=0; col < width; col++) ++// BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); ++// } ++// free (pixel); ++// fclose (fp); ++// memset (cblack, 0, sizeof cblack); ++// black = 0; ++//} + + void CLASS gamma_curve (double pwr, double ts, int mode, int imax) + { +@@ -4093,94 +4417,94 @@ + } + #endif + +-void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) +-{ +- int i; +- for (i=0; i < sc; i++) +- temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; +- for (; i+sc < size; i++) +- temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; +- for (; i < size; i++) +- temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; +-} +- +-void CLASS wavelet_denoise() +-{ +- float *fimg=0, *temp, thold, mul[2], avg, diff; +- int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; +- ushort *window[4]; +- static const float noise[] = +- { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; +- +- if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); +- +- while (maximum << scale < 0x10000) scale++; +- maximum <<= --scale; +- black <<= scale; +- FORC4 cblack[c] <<= scale; +- if ((size = iheight*iwidth) < 0x15550000) +- fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); +- merror (fimg, "wavelet_denoise()"); +- temp = fimg + size*3; +- if ((nc = colors) == 3 && filters) nc++; +- FORC(nc) { /* denoise R,G1,B,G3 individually */ +- for (i=0; i < size; i++) +- fimg[i] = 256 * sqrt(image[i][c] << scale); +- for (hpass=lev=0; lev < 5; lev++) { +- lpass = size*((lev & 1)+1); +- for (row=0; row < iheight; row++) { +- hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); +- for (col=0; col < iwidth; col++) +- fimg[lpass + row*iwidth + col] = temp[col] * 0.25; +- } +- for (col=0; col < iwidth; col++) { +- hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); +- for (row=0; row < iheight; row++) +- fimg[lpass + row*iwidth + col] = temp[row] * 0.25; +- } +- thold = threshold * noise[lev]; +- for (i=0; i < size; i++) { +- fimg[hpass+i] -= fimg[lpass+i]; +- if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; +- else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; +- else fimg[hpass+i] = 0; +- if (hpass) fimg[i] += fimg[hpass+i]; +- } +- hpass = lpass; +- } +- for (i=0; i < size; i++) +- image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); +- } +- if (filters && colors == 3) { /* pull G1 and G3 closer together */ +- for (row=0; row < 2; row++) { +- mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; +- blk[row] = cblack[FC(row,0) | 1]; +- } +- for (i=0; i < 4; i++) +- window[i] = (ushort *) fimg + width*i; +- for (wlast=-1, row=1; row < height-1; row++) { +- while (wlast < row+1) { +- for (wlast++, i=0; i < 4; i++) +- window[(i+3) & 3] = window[i]; +- for (col = FC(wlast,1) & 1; col < width; col+=2) +- window[2][col] = BAYER(wlast,col); +- } +- thold = threshold/512; +- for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { +- avg = ( window[0][col-1] + window[0][col+1] + +- window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) +- * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; +- avg = avg < 0 ? 0 : sqrt(avg); +- diff = sqrt(BAYER(row,col)) - avg; +- if (diff < -thold) diff += thold; +- else if (diff > thold) diff -= thold; +- else diff = 0; +- BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); +- } +- } +- } +- free (fimg); +-} ++//void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) ++//{ ++// int i; ++// for (i=0; i < sc; i++) ++// temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; ++// for (; i+sc < size; i++) ++// temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; ++// for (; i < size; i++) ++// temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; ++//} ++ ++//void CLASS wavelet_denoise() ++//{ ++// float *fimg=0, *temp, thold, mul[2], avg, diff; ++// int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; ++// ushort *window[4]; ++// static const float noise[] = ++// { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; ++// ++// if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); ++// ++// while (maximum << scale < 0x10000) scale++; ++// maximum <<= --scale; ++// black <<= scale; ++// FORC4 cblack[c] <<= scale; ++// if ((size = iheight*iwidth) < 0x15550000) ++// fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); ++// merror (fimg, "wavelet_denoise()"); ++// temp = fimg + size*3; ++// if ((nc = colors) == 3 && filters) nc++; ++// FORC(nc) { /* denoise R,G1,B,G3 individually */ ++// for (i=0; i < size; i++) ++// fimg[i] = 256 * sqrt(image[i][c] << scale); ++// for (hpass=lev=0; lev < 5; lev++) { ++// lpass = size*((lev & 1)+1); ++// for (row=0; row < iheight; row++) { ++// hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); ++// for (col=0; col < iwidth; col++) ++// fimg[lpass + row*iwidth + col] = temp[col] * 0.25; ++// } ++// for (col=0; col < iwidth; col++) { ++// hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); ++// for (row=0; row < iheight; row++) ++// fimg[lpass + row*iwidth + col] = temp[row] * 0.25; ++// } ++// thold = threshold * noise[lev]; ++// for (i=0; i < size; i++) { ++// fimg[hpass+i] -= fimg[lpass+i]; ++// if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; ++// else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; ++// else fimg[hpass+i] = 0; ++// if (hpass) fimg[i] += fimg[hpass+i]; ++// } ++// hpass = lpass; ++// } ++// for (i=0; i < size; i++) ++// image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); ++// } ++// if (filters && colors == 3) { /* pull G1 and G3 closer together */ ++// for (row=0; row < 2; row++) { ++// mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; ++// blk[row] = cblack[FC(row,0) | 1]; ++// } ++// for (i=0; i < 4; i++) ++// window[i] = (ushort *) fimg + width*i; ++// for (wlast=-1, row=1; row < height-1; row++) { ++// while (wlast < row+1) { ++// for (wlast++, i=0; i < 4; i++) ++// window[(i+3) & 3] = window[i]; ++// for (col = FC(wlast,1) & 1; col < width; col+=2) ++// window[2][col] = BAYER(wlast,col); ++// } ++// thold = threshold/512; ++// for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { ++// avg = ( window[0][col-1] + window[0][col+1] + ++// window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) ++// * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; ++// avg = avg < 0 ? 0 : sqrt(avg); ++// diff = sqrt(BAYER(row,col)) - avg; ++// if (diff < -thold) diff += thold; ++// else if (diff > thold) diff -= thold; ++// else diff = 0; ++// BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); ++// } ++// } ++// } ++// free (fimg); ++//} + + void CLASS scale_colors() + { +@@ -4238,7 +4562,7 @@ + if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; + dark = black; + sat = maximum; +- if (threshold) wavelet_denoise(); ++// if (threshold) wavelet_denoise(); + maximum -= black; + for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { + if (dmin > pre_mul[c]) +@@ -4344,776 +4668,440 @@ + if (half_size) filters = 0; + } + +-void CLASS border_interpolate (int border) +-{ +- unsigned row, col, y, x, f, c, sum[8]; +- +- for (row=0; row < height; row++) +- for (col=0; col < width; col++) { +- if (col==border && row >= border && row < height-border) +- col = width-border; +- memset (sum, 0, sizeof sum); +- for (y=row-1; y != row+2; y++) +- for (x=col-1; x != col+2; x++) +- if (y < height && x < width) { +- f = fcol(y,x); +- sum[f] += image[y*width+x][f]; +- sum[f+4]++; +- } +- f = fcol(row,col); +- FORCC if (c != f && sum[c+4]) +- image[row*width+col][c] = sum[c] / sum[c+4]; +- } +-} +- -void CLASS lin_interpolate() -{ - int code[16][16][32], size=16, *ip, sum[4]; @@ -884,8 +1342,7 @@ - This algorithm is officially called: - - "Interpolation using a Threshold-based variable number of gradients" -+/* RT: delete interpolation functions */ - +- - described in http://scien.stanford.edu/pages/labsite/1999/psych221/projects/99/tingchen/algodep/vargra.html - - I've extended the basic idea to work with non-Bayer filter arrays. @@ -1071,13 +1528,271 @@ - pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); - } -} - - void CLASS cielab (ushort rgb[3], short lab[3]) - { -@@ -4864,112 +4957,7 @@ - } - #undef fcol - +- +-void CLASS cielab (ushort rgb[3], short lab[3]) +-{ +- int c, i, j, k; +- float r, xyz[3]; +- static float cbrt[0x10000], xyz_cam[3][4]; +- +- if (!rgb) { +- for (i=0; i < 0x10000; i++) { +- r = i / 65535.0; +- cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; +- } +- for (i=0; i < 3; i++) +- for (j=0; j < colors; j++) +- for (xyz_cam[i][j] = k=0; k < 3; k++) +- xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; +- return; +- } +- xyz[0] = xyz[1] = xyz[2] = 0.5; +- FORCC { +- xyz[0] += xyz_cam[0][c] * rgb[c]; +- xyz[1] += xyz_cam[1][c] * rgb[c]; +- xyz[2] += xyz_cam[2][c] * rgb[c]; +- } +- xyz[0] = cbrt[CLIP((int) xyz[0])]; +- xyz[1] = cbrt[CLIP((int) xyz[1])]; +- xyz[2] = cbrt[CLIP((int) xyz[2])]; +- lab[0] = 64 * (116 * xyz[1] - 16); +- lab[1] = 64 * 500 * (xyz[0] - xyz[1]); +- lab[2] = 64 * 200 * (xyz[1] - xyz[2]); +-} +- +-#define TS 512 /* Tile Size */ +-#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] +- +-/* +- Frank Markesteijn's algorithm for Fuji X-Trans sensors +- */ +-void CLASS xtrans_interpolate (int passes) +-{ +- int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; +- int val, ndir, pass, hm[8], avg[4], color[3][8]; +- static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, +- patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, +- { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, +- dir[4] = { 1,TS,TS+1,TS-1 }; +- short allhex[3][3][2][8], *hex; +- ushort min, max, sgrow, sgcol; +- ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; +- short (*lab) [TS][3], (*lix)[3]; +- float (*drv)[TS][TS], diff[6], tr; +- char (*homo)[TS][TS], *buffer; +- +- if (verbose) +- fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); +- +- cielab (0,0); +- ndir = 4 << (passes > 1); +- buffer = (char *) malloc (TS*TS*(ndir*11+6)); +- merror (buffer, "xtrans_interpolate()"); +- rgb = (ushort(*)[TS][TS][3]) buffer; +- lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); +- drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); +- homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); +- +-/* Map a green hexagon around each non-green pixel and vice versa: */ +- for (row=0; row < 3; row++) +- for (col=0; col < 3; col++) +- for (ng=d=0; d < 10; d+=2) { +- g = fcol(row,col) == 1; +- if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; +- if (ng == 4) { sgrow = row; sgcol = col; } +- if (ng == g+1) FORC(8) { +- v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; +- h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; +- allhex[row][col][0][c^(g*2 & d)] = h + v*width; +- allhex[row][col][1][c^(g*2 & d)] = h + v*TS; +- } +- } +- +-/* Set green1 and green3 to the minimum and maximum allowed values: */ +- for (row=2; row < height-2; row++) +- for (min=~(max=0), col=2; col < width-2; col++) { +- if (fcol(row,col) == 1 && (min=~(max=0))) continue; +- pix = image + row*width + col; +- hex = allhex[row % 3][col % 3][0]; +- if (!max) FORC(6) { +- val = pix[hex[c]][1]; +- if (min > val) min = val; +- if (max < val) max = val; +- } +- pix[0][1] = min; +- pix[0][3] = max; +- switch ((row-sgrow) % 3) { +- case 1: if (row < height-3) { row++; col--; } break; +- case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; +- } +- } +- +- for (top=3; top < height-19; top += TS-16) +- for (left=3; left < width-19; left += TS-16) { +- mrow = MIN (top+TS, height-3); +- mcol = MIN (left+TS, width-3); +- for (row=top; row < mrow; row++) +- for (col=left; col < mcol; col++) +- memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); +- FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); +- +-/* Interpolate green horizontally, vertically, and along both diagonals: */ +- for (row=top; row < mrow; row++) +- for (col=left; col < mcol; col++) { +- if ((f = fcol(row,col)) == 1) continue; +- pix = image + row*width + col; +- hex = allhex[row % 3][col % 3][0]; +- color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - +- 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); +- color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + +- 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); +- FORC(2) color[1][2+c] = +- 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * +- (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); +- FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = +- LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); +- } +- +- for (pass=0; pass < passes; pass++) { +- if (pass == 1) +- memcpy (rgb+=4, buffer, 4*sizeof *rgb); +- +-/* Recalculate green from interpolated values of closer pixels: */ +- if (pass) { +- for (row=top+2; row < mrow-2; row++) +- for (col=left+2; col < mcol-2; col++) { +- if ((f = fcol(row,col)) == 1) continue; +- pix = image + row*width + col; +- hex = allhex[row % 3][col % 3][1]; +- for (d=3; d < 6; d++) { +- rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; +- val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] +- - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; +- rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); +- } +- } +- } +- +-/* Interpolate red and blue values for solitary green pixels: */ +- for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) +- for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { +- rix = &rgb[0][row-top][col-left]; +- h = fcol(row,col+1); +- memset (diff, 0, sizeof diff); +- for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { +- for (c=0; c < 2; c++, h^=2) { +- g = 2*rix[0][1] - rix[i< 1) +- diff[d] += SQR (rix[i< 1 && (d & 1)) +- if (diff[d-1] < diff[d]) +- FORC(2) color[c*2][d] = color[c*2][d-1]; +- if (d < 2 || (d & 1)) { +- FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); +- rix += TS*TS; +- } +- } +- } +- +-/* Interpolate red for blue pixels and vice versa: */ +- for (row=top+3; row < mrow-3; row++) +- for (col=left+3; col < mcol-3; col++) { +- if ((f = 2-fcol(row,col)) == 1) continue; +- rix = &rgb[0][row-top][col-left]; +- c = (row-sgrow) % 3 ? TS:1; +- h = 3 * (c ^ TS ^ 1); +- for (d=0; d < 4; d++, rix += TS*TS) { +- i = d > 1 || ((d ^ c) & 1) || +- ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < +- 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; +- rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + +- 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); +- } +- } +- +-/* Fill in red and blue for 2x2 blocks of green: */ +- for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) +- for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { +- rix = &rgb[0][row-top][col-left]; +- hex = allhex[row % 3][col % 3][1]; +- for (d=0; d < ndir; d+=2, rix += TS*TS) +- if (hex[d] + hex[d+1]) { +- g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; +- for (c=0; c < 4; c+=2) rix[0][c] = +- CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); +- } else { +- g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; +- for (c=0; c < 4; c+=2) rix[0][c] = +- CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); +- } +- } +- } +- rgb = (ushort(*)[TS][TS][3]) buffer; +- mrow -= top; +- mcol -= left; +- +-/* Convert to CIELab and differentiate in all directions: */ +- for (d=0; d < ndir; d++) { +- for (row=2; row < mrow-2; row++) +- for (col=2; col < mcol-2; col++) +- cielab (rgb[d][row][col], lab[row][col]); +- for (f=dir[d & 3],row=3; row < mrow-3; row++) +- for (col=3; col < mcol-3; col++) { +- lix = &lab[row][col]; +- g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; +- drv[d][row][col] = SQR(g) +- + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) +- + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); +- } +- } +- +-/* Build homogeneity maps from the derivatives: */ +- memset(homo, 0, ndir*TS*TS); +- for (row=4; row < mrow-4; row++) +- for (col=4; col < mcol-4; col++) { +- for (tr=FLT_MAX, d=0; d < ndir; d++) +- if (tr > drv[d][row][col]) +- tr = drv[d][row][col]; +- tr *= 8; +- for (d=0; d < ndir; d++) +- for (v=-1; v <= 1; v++) +- for (h=-1; h <= 1; h++) +- if (drv[d][row+v][col+h] <= tr) +- homo[d][row][col]++; +- } +- +-/* Average the most homogenous pixels for the final result: */ +- if (height-top < TS+4) mrow = height-top+2; +- if (width-left < TS+4) mcol = width-left+2; +- for (row = MIN(top,8); row < mrow-8; row++) +- for (col = MIN(left,8); col < mcol-8; col++) { +- for (d=0; d < ndir; d++) +- for (hm[d]=0, v=-2; v <= 2; v++) +- for (h=-2; h <= 2; h++) +- hm[d] += homo[d][row+v][col+h]; +- for (d=0; d < ndir-4; d++) +- if (hm[d] < hm[d+4]) hm[d ] = 0; else +- if (hm[d] > hm[d+4]) hm[d+4] = 0; +- for (max=hm[0],d=1; d < ndir; d++) +- if (max < hm[d]) max = hm[d]; +- max -= max >> 3; +- memset (avg, 0, sizeof avg); +- for (d=0; d < ndir; d++) +- if (hm[d] >= max) { +- FORC3 avg[c] += rgb[d][row][col][c]; +- avg[3]++; +- } +- FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; +- } +- } +- free(buffer); +- border_interpolate(8); +-} +-#undef fcol +- -/* - Adaptive Homogeneity-Directed interpolation is based on - the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. @@ -1103,7 +1818,7 @@ - - for (top=2; top < height-5; top += TS-6) - for (left=2; left < width-5; left += TS-6) { - +- -/* Interpolate green horizontally and vertically: */ - for (row=top; row < top+TS && row < height-2; row++) { - col = left + (FC(row,left) & 1); @@ -1184,9 +1899,587 @@ - } - free (buffer); -} - #undef TS +-#undef TS +- +-void CLASS median_filter() +-{ +- ushort (*pix)[4]; +- int pass, c, i, j, k, med[9]; +- static const uchar opt[] = /* Optimal 9-element median search */ +- { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, +- 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; +- +- for (pass=1; pass <= med_passes; pass++) { +- if (verbose) +- fprintf (stderr,_("Median filter pass %d...\n"), pass); +- for (c=0; c < 3; c+=2) { +- for (pix = image; pix < image+width*height; pix++) +- pix[0][3] = pix[0][c]; +- for (pix = image+width; pix < image+width*(height-1); pix++) { +- if ((pix-image+1) % width < 2) continue; +- for (k=0, i = -width; i <= width; i += width) +- for (j = i-1; j <= i+1; j++) +- med[k++] = pix[j][3] - pix[j][1]; +- for (i=0; i < sizeof opt; i+=2) +- if (med[opt[i]] > med[opt[i+1]]) +- SWAP (med[opt[i]] , med[opt[i+1]]); +- pix[0][c] = CLIP(med[4] + pix[0][1]); +- } +- } +- } +-} +- +-void CLASS blend_highlights() +-{ +- int clip=INT_MAX, row, col, c, i, j; +- static const float trans[2][4][4] = +- { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, +- { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; +- static const float itrans[2][4][4] = +- { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, +- { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; +- float cam[2][4], lab[2][4], sum[2], chratio; +- +- if ((unsigned) (colors-3) > 1) return; +- if (verbose) fprintf (stderr,_("Blending highlights...\n")); +- FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; +- for (row=0; row < height; row++) +- for (col=0; col < width; col++) { +- FORCC if (image[row*width+col][c] > clip) break; +- if (c == colors) continue; +- FORCC { +- cam[0][c] = image[row*width+col][c]; +- cam[1][c] = MIN(cam[0][c],clip); +- } +- for (i=0; i < 2; i++) { +- FORCC for (lab[i][c]=j=0; j < colors; j++) +- lab[i][c] += trans[colors-3][c][j] * cam[i][j]; +- for (sum[i]=0,c=1; c < colors; c++) +- sum[i] += SQR(lab[i][c]); +- } +- chratio = sqrt(sum[1]/sum[0]); +- for (c=1; c < colors; c++) +- lab[0][c] *= chratio; +- FORCC for (cam[0][c]=j=0; j < colors; j++) +- cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; +- FORCC image[row*width+col][c] = cam[0][c] / colors; +- } +-} +- +-#define SCALE (4 >> shrink) +-void CLASS recover_highlights() +-{ +- float *map, sum, wgt, grow; +- int hsat[4], count, spread, change, val, i; +- unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; +- ushort *pixel; +- static const signed char dir[8][2] = +- { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; +- +- if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); +- +- grow = pow (2, 4-highlight); +- FORCC hsat[c] = 32000 * pre_mul[c]; +- for (kc=0, c=1; c < colors; c++) +- if (pre_mul[kc] < pre_mul[c]) kc = c; +- high = height / SCALE; +- wide = width / SCALE; +- map = (float *) calloc (high, wide*sizeof *map); +- merror (map, "recover_highlights()"); +- FORCC if (c != kc) { +- memset (map, 0, high*wide*sizeof *map); +- for (mrow=0; mrow < high; mrow++) +- for (mcol=0; mcol < wide; mcol++) { +- sum = wgt = count = 0; +- for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) +- for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { +- pixel = image[row*width+col]; +- if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { +- sum += pixel[c]; +- wgt += pixel[kc]; +- count++; +- } +- } +- if (count == SCALE*SCALE) +- map[mrow*wide+mcol] = sum / wgt; +- } +- for (spread = 32/grow; spread--; ) { +- for (mrow=0; mrow < high; mrow++) +- for (mcol=0; mcol < wide; mcol++) { +- if (map[mrow*wide+mcol]) continue; +- sum = count = 0; +- for (d=0; d < 8; d++) { +- y = mrow + dir[d][0]; +- x = mcol + dir[d][1]; +- if (y < high && x < wide && map[y*wide+x] > 0) { +- sum += (1 + (d & 1)) * map[y*wide+x]; +- count += 1 + (d & 1); +- } +- } +- if (count > 3) +- map[mrow*wide+mcol] = - (sum+grow) / (count+grow); +- } +- for (change=i=0; i < high*wide; i++) +- if (map[i] < 0) { +- map[i] = -map[i]; +- change = 1; +- } +- if (!change) break; +- } +- for (i=0; i < high*wide; i++) +- if (map[i] == 0) map[i] = 1; +- for (mrow=0; mrow < high; mrow++) +- for (mcol=0; mcol < wide; mcol++) { +- for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) +- for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { +- pixel = image[row*width+col]; +- if (pixel[c] / hsat[c] > 1) { +- val = pixel[kc] * map[mrow*wide+mcol]; +- if (pixel[c] < val) pixel[c] = CLIP(val); +- } +- } +- } +- } +- free (map); +-} +-#undef SCALE ++//void CLASS border_interpolate (int border) ++//{ ++// unsigned row, col, y, x, f, c, sum[8]; ++// ++// for (row=0; row < height; row++) ++// for (col=0; col < width; col++) { ++// if (col==border && row >= border && row < height-border) ++// col = width-border; ++// memset (sum, 0, sizeof sum); ++// for (y=row-1; y != row+2; y++) ++// for (x=col-1; x != col+2; x++) ++// if (y < height && x < width) { ++// f = fcol(y,x); ++// sum[f] += image[y*width+x][f]; ++// sum[f+4]++; ++// } ++// f = fcol(row,col); ++// FORCC if (c != f && sum[c+4]) ++// image[row*width+col][c] = sum[c] / sum[c+4]; ++// } ++//} ++ ++/* RT: delete interpolation functions */ ++ ++ ++//void CLASS cielab (ushort rgb[3], short lab[3]) ++//{ ++// int c, i, j, k; ++// float r, xyz[3]; ++// static float cbrt[0x10000], xyz_cam[3][4]; ++// ++// if (!rgb) { ++// for (i=0; i < 0x10000; i++) { ++// r = i / 65535.0; ++// cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; ++// } ++// for (i=0; i < 3; i++) ++// for (j=0; j < colors; j++) ++// for (xyz_cam[i][j] = k=0; k < 3; k++) ++// xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; ++// return; ++// } ++// xyz[0] = xyz[1] = xyz[2] = 0.5; ++// FORCC { ++// xyz[0] += xyz_cam[0][c] * rgb[c]; ++// xyz[1] += xyz_cam[1][c] * rgb[c]; ++// xyz[2] += xyz_cam[2][c] * rgb[c]; ++// } ++// xyz[0] = cbrt[CLIP((int) xyz[0])]; ++// xyz[1] = cbrt[CLIP((int) xyz[1])]; ++// xyz[2] = cbrt[CLIP((int) xyz[2])]; ++// lab[0] = 64 * (116 * xyz[1] - 16); ++// lab[1] = 64 * 500 * (xyz[0] - xyz[1]); ++// lab[2] = 64 * 200 * (xyz[1] - xyz[2]); ++//} ++// ++//#define TS 512 /* Tile Size */ ++//#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] ++// ++///* ++// Frank Markesteijn's algorithm for Fuji X-Trans sensors ++// */ ++//void CLASS xtrans_interpolate (int passes) ++//{ ++// int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; ++// int val, ndir, pass, hm[8], avg[4], color[3][8]; ++// static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, ++// patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, ++// { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, ++// dir[4] = { 1,TS,TS+1,TS-1 }; ++// short allhex[3][3][2][8], *hex; ++// ushort min, max, sgrow, sgcol; ++// ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; ++// short (*lab) [TS][3], (*lix)[3]; ++// float (*drv)[TS][TS], diff[6], tr; ++// char (*homo)[TS][TS], *buffer; ++// ++// if (verbose) ++// fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); ++// ++// cielab (0,0); ++// ndir = 4 << (passes > 1); ++// buffer = (char *) malloc (TS*TS*(ndir*11+6)); ++// merror (buffer, "xtrans_interpolate()"); ++// rgb = (ushort(*)[TS][TS][3]) buffer; ++// lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); ++// drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); ++// homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); ++// ++///* Map a green hexagon around each non-green pixel and vice versa: */ ++// for (row=0; row < 3; row++) ++// for (col=0; col < 3; col++) ++// for (ng=d=0; d < 10; d+=2) { ++// g = fcol(row,col) == 1; ++// if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; ++// if (ng == 4) { sgrow = row; sgcol = col; } ++// if (ng == g+1) FORC(8) { ++// v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; ++// h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; ++// allhex[row][col][0][c^(g*2 & d)] = h + v*width; ++// allhex[row][col][1][c^(g*2 & d)] = h + v*TS; ++// } ++// } ++// ++///* Set green1 and green3 to the minimum and maximum allowed values: */ ++// for (row=2; row < height-2; row++) ++// for (min=~(max=0), col=2; col < width-2; col++) { ++// if (fcol(row,col) == 1 && (min=~(max=0))) continue; ++// pix = image + row*width + col; ++// hex = allhex[row % 3][col % 3][0]; ++// if (!max) FORC(6) { ++// val = pix[hex[c]][1]; ++// if (min > val) min = val; ++// if (max < val) max = val; ++// } ++// pix[0][1] = min; ++// pix[0][3] = max; ++// switch ((row-sgrow) % 3) { ++// case 1: if (row < height-3) { row++; col--; } break; ++// case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; ++// } ++// } ++// ++// for (top=3; top < height-19; top += TS-16) ++// for (left=3; left < width-19; left += TS-16) { ++// mrow = MIN (top+TS, height-3); ++// mcol = MIN (left+TS, width-3); ++// for (row=top; row < mrow; row++) ++// for (col=left; col < mcol; col++) ++// memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); ++// FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); ++// ++///* Interpolate green horizontally, vertically, and along both diagonals: */ ++// for (row=top; row < mrow; row++) ++// for (col=left; col < mcol; col++) { ++// if ((f = fcol(row,col)) == 1) continue; ++// pix = image + row*width + col; ++// hex = allhex[row % 3][col % 3][0]; ++// color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - ++// 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); ++// color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + ++// 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); ++// FORC(2) color[1][2+c] = ++// 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * ++// (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); ++// FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = ++// LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); ++// } ++// ++// for (pass=0; pass < passes; pass++) { ++// if (pass == 1) ++// memcpy (rgb+=4, buffer, 4*sizeof *rgb); ++// ++///* Recalculate green from interpolated values of closer pixels: */ ++// if (pass) { ++// for (row=top+2; row < mrow-2; row++) ++// for (col=left+2; col < mcol-2; col++) { ++// if ((f = fcol(row,col)) == 1) continue; ++// pix = image + row*width + col; ++// hex = allhex[row % 3][col % 3][1]; ++// for (d=3; d < 6; d++) { ++// rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; ++// val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] ++// - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; ++// rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); ++// } ++// } ++// } ++// ++///* Interpolate red and blue values for solitary green pixels: */ ++// for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) ++// for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { ++// rix = &rgb[0][row-top][col-left]; ++// h = fcol(row,col+1); ++// memset (diff, 0, sizeof diff); ++// for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { ++// for (c=0; c < 2; c++, h^=2) { ++// g = 2*rix[0][1] - rix[i< 1) ++// diff[d] += SQR (rix[i< 1 && (d & 1)) ++// if (diff[d-1] < diff[d]) ++// FORC(2) color[c*2][d] = color[c*2][d-1]; ++// if (d < 2 || (d & 1)) { ++// FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); ++// rix += TS*TS; ++// } ++// } ++// } ++// ++///* Interpolate red for blue pixels and vice versa: */ ++// for (row=top+3; row < mrow-3; row++) ++// for (col=left+3; col < mcol-3; col++) { ++// if ((f = 2-fcol(row,col)) == 1) continue; ++// rix = &rgb[0][row-top][col-left]; ++// c = (row-sgrow) % 3 ? TS:1; ++// h = 3 * (c ^ TS ^ 1); ++// for (d=0; d < 4; d++, rix += TS*TS) { ++// i = d > 1 || ((d ^ c) & 1) || ++// ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < ++// 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; ++// rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + ++// 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); ++// } ++// } ++// ++///* Fill in red and blue for 2x2 blocks of green: */ ++// for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) ++// for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { ++// rix = &rgb[0][row-top][col-left]; ++// hex = allhex[row % 3][col % 3][1]; ++// for (d=0; d < ndir; d+=2, rix += TS*TS) ++// if (hex[d] + hex[d+1]) { ++// g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; ++// for (c=0; c < 4; c+=2) rix[0][c] = ++// CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); ++// } else { ++// g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; ++// for (c=0; c < 4; c+=2) rix[0][c] = ++// CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); ++// } ++// } ++// } ++// rgb = (ushort(*)[TS][TS][3]) buffer; ++// mrow -= top; ++// mcol -= left; ++// ++///* Convert to CIELab and differentiate in all directions: */ ++// for (d=0; d < ndir; d++) { ++// for (row=2; row < mrow-2; row++) ++// for (col=2; col < mcol-2; col++) ++// cielab (rgb[d][row][col], lab[row][col]); ++// for (f=dir[d & 3],row=3; row < mrow-3; row++) ++// for (col=3; col < mcol-3; col++) { ++// lix = &lab[row][col]; ++// g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; ++// drv[d][row][col] = SQR(g) ++// + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) ++// + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); ++// } ++// } ++// ++///* Build homogeneity maps from the derivatives: */ ++// memset(homo, 0, ndir*TS*TS); ++// for (row=4; row < mrow-4; row++) ++// for (col=4; col < mcol-4; col++) { ++// for (tr=FLT_MAX, d=0; d < ndir; d++) ++// if (tr > drv[d][row][col]) ++// tr = drv[d][row][col]; ++// tr *= 8; ++// for (d=0; d < ndir; d++) ++// for (v=-1; v <= 1; v++) ++// for (h=-1; h <= 1; h++) ++// if (drv[d][row+v][col+h] <= tr) ++// homo[d][row][col]++; ++// } ++// ++///* Average the most homogenous pixels for the final result: */ ++// if (height-top < TS+4) mrow = height-top+2; ++// if (width-left < TS+4) mcol = width-left+2; ++// for (row = MIN(top,8); row < mrow-8; row++) ++// for (col = MIN(left,8); col < mcol-8; col++) { ++// for (d=0; d < ndir; d++) ++// for (hm[d]=0, v=-2; v <= 2; v++) ++// for (h=-2; h <= 2; h++) ++// hm[d] += homo[d][row+v][col+h]; ++// for (d=0; d < ndir-4; d++) ++// if (hm[d] < hm[d+4]) hm[d ] = 0; else ++// if (hm[d] > hm[d+4]) hm[d+4] = 0; ++// for (max=hm[0],d=1; d < ndir; d++) ++// if (max < hm[d]) max = hm[d]; ++// max -= max >> 3; ++// memset (avg, 0, sizeof avg); ++// for (d=0; d < ndir; d++) ++// if (hm[d] >= max) { ++// FORC3 avg[c] += rgb[d][row][col][c]; ++// avg[3]++; ++// } ++// FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; ++// } ++// } ++// free(buffer); ++// border_interpolate(8); ++//} ++//#undef fcol ++// ++// ++//#undef TS ++ ++//void CLASS median_filter() ++//{ ++// ushort (*pix)[4]; ++// int pass, c, i, j, k, med[9]; ++// static const uchar opt[] = /* Optimal 9-element median search */ ++// { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, ++// 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; ++// ++// for (pass=1; pass <= med_passes; pass++) { ++// if (verbose) ++// fprintf (stderr,_("Median filter pass %d...\n"), pass); ++// for (c=0; c < 3; c+=2) { ++// for (pix = image; pix < image+width*height; pix++) ++// pix[0][3] = pix[0][c]; ++// for (pix = image+width; pix < image+width*(height-1); pix++) { ++// if ((pix-image+1) % width < 2) continue; ++// for (k=0, i = -width; i <= width; i += width) ++// for (j = i-1; j <= i+1; j++) ++// med[k++] = pix[j][3] - pix[j][1]; ++// for (i=0; i < sizeof opt; i+=2) ++// if (med[opt[i]] > med[opt[i+1]]) ++// SWAP (med[opt[i]] , med[opt[i+1]]); ++// pix[0][c] = CLIP(med[4] + pix[0][1]); ++// } ++// } ++// } ++//} ++// ++//void CLASS blend_highlights() ++//{ ++// int clip=INT_MAX, row, col, c, i, j; ++// static const float trans[2][4][4] = ++// { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, ++// { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; ++// static const float itrans[2][4][4] = ++// { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, ++// { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; ++// float cam[2][4], lab[2][4], sum[2], chratio; ++// ++// if ((unsigned) (colors-3) > 1) return; ++// if (verbose) fprintf (stderr,_("Blending highlights...\n")); ++// FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; ++// for (row=0; row < height; row++) ++// for (col=0; col < width; col++) { ++// FORCC if (image[row*width+col][c] > clip) break; ++// if (c == colors) continue; ++// FORCC { ++// cam[0][c] = image[row*width+col][c]; ++// cam[1][c] = MIN(cam[0][c],clip); ++// } ++// for (i=0; i < 2; i++) { ++// FORCC for (lab[i][c]=j=0; j < colors; j++) ++// lab[i][c] += trans[colors-3][c][j] * cam[i][j]; ++// for (sum[i]=0,c=1; c < colors; c++) ++// sum[i] += SQR(lab[i][c]); ++// } ++// chratio = sqrt(sum[1]/sum[0]); ++// for (c=1; c < colors; c++) ++// lab[0][c] *= chratio; ++// FORCC for (cam[0][c]=j=0; j < colors; j++) ++// cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; ++// FORCC image[row*width+col][c] = cam[0][c] / colors; ++// } ++//} ++// ++//#define SCALE (4 >> shrink) ++//void CLASS recover_highlights() ++//{ ++// float *map, sum, wgt, grow; ++// int hsat[4], count, spread, change, val, i; ++// unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; ++// ushort *pixel; ++// static const signed char dir[8][2] = ++// { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; ++// ++// if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); ++// ++// grow = pow (2, 4-highlight); ++// FORCC hsat[c] = 32000 * pre_mul[c]; ++// for (kc=0, c=1; c < colors; c++) ++// if (pre_mul[kc] < pre_mul[c]) kc = c; ++// high = height / SCALE; ++// wide = width / SCALE; ++// map = (float *) calloc (high, wide*sizeof *map); ++// merror (map, "recover_highlights()"); ++// FORCC if (c != kc) { ++// memset (map, 0, high*wide*sizeof *map); ++// for (mrow=0; mrow < high; mrow++) ++// for (mcol=0; mcol < wide; mcol++) { ++// sum = wgt = count = 0; ++// for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) ++// for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { ++// pixel = image[row*width+col]; ++// if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { ++// sum += pixel[c]; ++// wgt += pixel[kc]; ++// count++; ++// } ++// } ++// if (count == SCALE*SCALE) ++// map[mrow*wide+mcol] = sum / wgt; ++// } ++// for (spread = 32/grow; spread--; ) { ++// for (mrow=0; mrow < high; mrow++) ++// for (mcol=0; mcol < wide; mcol++) { ++// if (map[mrow*wide+mcol]) continue; ++// sum = count = 0; ++// for (d=0; d < 8; d++) { ++// y = mrow + dir[d][0]; ++// x = mcol + dir[d][1]; ++// if (y < high && x < wide && map[y*wide+x] > 0) { ++// sum += (1 + (d & 1)) * map[y*wide+x]; ++// count += 1 + (d & 1); ++// } ++// } ++// if (count > 3) ++// map[mrow*wide+mcol] = - (sum+grow) / (count+grow); ++// } ++// for (change=i=0; i < high*wide; i++) ++// if (map[i] < 0) { ++// map[i] = -map[i]; ++// change = 1; ++// } ++// if (!change) break; ++// } ++// for (i=0; i < high*wide; i++) ++// if (map[i] == 0) map[i] = 1; ++// for (mrow=0; mrow < high; mrow++) ++// for (mcol=0; mcol < wide; mcol++) { ++// for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) ++// for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { ++// pixel = image[row*width+col]; ++// if (pixel[c] / hsat[c] > 1) { ++// val = pixel[kc] * map[mrow*wide+mcol]; ++// if (pixel[c] < val) pixel[c] = CLIP(val); ++// } ++// } ++// } ++// } ++// free (map); ++//} ++//#undef SCALE - void CLASS median_filter() + void CLASS tiff_get (unsigned base, + unsigned *tag, unsigned *type, unsigned *len, unsigned *save) @@ -5139,7 +5127,7 @@ } } @@ -1783,9 +3076,141 @@ is_raw = 0; #ifdef NO_JASPER if (load_raw == &CLASS redcine_load_raw) { -@@ -9452,199 +9583,250 @@ +@@ -9402,249 +9533,300 @@ + if (flip == UINT_MAX) flip = 0; } - #endif + +-#ifndef NO_LCMS +-void CLASS apply_profile (const char *input, const char *output) +-{ +- char *prof; +- cmsHPROFILE hInProfile=0, hOutProfile=0; +- cmsHTRANSFORM hTransform; +- FILE *fp; +- unsigned size; +- +- if (strcmp (input, "embed")) +- hInProfile = cmsOpenProfileFromFile (input, "r"); +- else if (profile_length) { +- prof = (char *) malloc (profile_length); +- merror (prof, "apply_profile()"); +- fseek (ifp, profile_offset, SEEK_SET); +- fread (prof, 1, profile_length, ifp); +- hInProfile = cmsOpenProfileFromMem (prof, profile_length); +- free (prof); +- } else +- fprintf (stderr,_("%s has no embedded profile.\n"), ifname); +- if (!hInProfile) return; +- if (!output) +- hOutProfile = cmsCreate_sRGBProfile(); +- else if ((fp = fopen (output, "rb"))) { +- fread (&size, 4, 1, fp); +- fseek (fp, 0, SEEK_SET); +- oprof = (unsigned *) malloc (size = ntohl(size)); +- merror (oprof, "apply_profile()"); +- fread (oprof, 1, size, fp); +- fclose (fp); +- if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { +- free (oprof); +- oprof = 0; ++//#ifndef NO_LCMS ++//void CLASS apply_profile (const char *input, const char *output) ++//{ ++// char *prof; ++// cmsHPROFILE hInProfile=0, hOutProfile=0; ++// cmsHTRANSFORM hTransform; ++// FILE *fp; ++// unsigned size; ++// ++// if (strcmp (input, "embed")) ++// hInProfile = cmsOpenProfileFromFile (input, "r"); ++// else if (profile_length) { ++// prof = (char *) malloc (profile_length); ++// merror (prof, "apply_profile()"); ++// fseek (ifp, profile_offset, SEEK_SET); ++// fread (prof, 1, profile_length, ifp); ++// hInProfile = cmsOpenProfileFromMem (prof, profile_length); ++// free (prof); ++// } else ++// fprintf (stderr,_("%s has no embedded profile.\n"), ifname); ++// if (!hInProfile) return; ++// if (!output) ++// hOutProfile = cmsCreate_sRGBProfile(); ++// else if ((fp = fopen (output, "rb"))) { ++// fread (&size, 4, 1, fp); ++// fseek (fp, 0, SEEK_SET); ++// oprof = (unsigned *) malloc (size = ntohl(size)); ++// merror (oprof, "apply_profile()"); ++// fread (oprof, 1, size, fp); ++// fclose (fp); ++// if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { ++// free (oprof); ++// oprof = 0; ++// } ++// } else ++// fprintf (stderr,_("Cannot open file %s!\n"), output); ++// if (!hOutProfile) goto quit; ++// if (verbose) ++// fprintf (stderr,_("Applying color profile...\n")); ++// hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, ++// hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); ++// cmsDoTransform (hTransform, image, image, width*height); ++// raw_color = 1; /* Don't use rgb_cam with a profile */ ++// cmsDeleteTransform (hTransform); ++// cmsCloseProfile (hOutProfile); ++//quit: ++// cmsCloseProfile (hInProfile); ++//} ++//#endif ++ ++/* RT: DNG Float */ ++ ++#include ++#include ++ ++static void decodeFPDeltaRow(Bytef * src, Bytef * dst, size_t tileWidth, size_t realTileWidth, int bytesps, int factor) { ++ // DecodeDeltaBytes ++ for (size_t col = factor; col < realTileWidth*bytesps; ++col) { ++ src[col] += src[col - factor]; ++ } ++ // Reorder bytes into the image ++ // 16 and 32-bit versions depend on local architecture, 24-bit does not ++ if (bytesps == 3) { ++ for (size_t col = 0; col < tileWidth; ++col) { ++ dst[col*3] = src[col]; ++ dst[col*3 + 1] = src[col + realTileWidth]; ++ dst[col*3 + 2] = src[col + realTileWidth*2]; + } +- } else +- fprintf (stderr,_("Cannot open file %s!\n"), output); +- if (!hOutProfile) goto quit; +- if (verbose) +- fprintf (stderr,_("Applying color profile...\n")); +- hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, +- hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); +- cmsDoTransform (hTransform, image, image, width*height); +- raw_color = 1; /* Don't use rgb_cam with a profile */ +- cmsDeleteTransform (hTransform); +- cmsCloseProfile (hOutProfile); +-quit: +- cmsCloseProfile (hInProfile); ++ } else { ++ union X { uint32_t x; uint8_t c; }; ++ if (((union X){1}).c) { ++ for (size_t col = 0; col < tileWidth; ++col) { ++ for (size_t byte = 0; byte < bytesps; ++byte) ++ dst[col*bytesps + byte] = src[col + realTileWidth*(bytesps-byte-1)]; // Little endian ++ } ++ } else { ++ for (size_t col = 0; col < tileWidth; ++col) { ++ for (size_t byte = 0; byte < bytesps; ++byte) ++ dst[col*bytesps + byte] = src[col + realTileWidth*byte]; ++ } ++ } ++ } ++ + } +-#endif -void CLASS convert_to_rgb() -{ @@ -1872,41 +3297,6 @@ - for (j=0; j < colors; j++) - for (out_cam[i][j] = k=0; k < 3; k++) - out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; -+/* RT: DNG Float */ -+ -+#include -+#include -+ -+static void decodeFPDeltaRow(Bytef * src, Bytef * dst, size_t tileWidth, size_t realTileWidth, int bytesps, int factor) { -+ // DecodeDeltaBytes -+ for (size_t col = factor; col < realTileWidth*bytesps; ++col) { -+ src[col] += src[col - factor]; -+ } -+ // Reorder bytes into the image -+ // 16 and 32-bit versions depend on local architecture, 24-bit does not -+ if (bytesps == 3) { -+ for (size_t col = 0; col < tileWidth; ++col) { -+ dst[col*3] = src[col]; -+ dst[col*3 + 1] = src[col + realTileWidth]; -+ dst[col*3 + 2] = src[col + realTileWidth*2]; -+ } -+ } else { -+ union X { uint32_t x; uint8_t c; }; -+ if (((union X){1}).c) { -+ for (size_t col = 0; col < tileWidth; ++col) { -+ for (size_t byte = 0; byte < bytesps; ++byte) -+ dst[col*bytesps + byte] = src[col + realTileWidth*(bytesps-byte-1)]; // Little endian -+ } -+ } else { -+ for (size_t col = 0; col < tileWidth; ++col) { -+ for (size_t byte = 0; byte < bytesps; ++byte) -+ dst[col*bytesps + byte] = src[col + realTileWidth*byte]; -+ } -+ } -+ } -+ -+} -+ +// From DNG SDK dng_utils.h +static inline uint32_t DNG_HalfToFloat(uint16_t halfValue) { + int32_t sign = (halfValue >> 15) & 0x00000001; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 22c5f91d9..1b1d460f3 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -962,24 +962,14 @@ void Crop::update (int todo) // all pipette buffer processing should be finished now PipetteBuffer::setReady(); - // switch back to rgb + // Computing the preview image, i.e. converting from lab->Monitor color space (soft-proofing disabled) or lab->Output profile->Monitor color space (soft-proofing enabled) parent->ipf.lab2monitorRgb (labnCrop, cropImg); if (cropImageListener) { - // this in output space held in parallel to allow analysis like shadow/highlight - Glib::ustring outProfile = params.icm.output; - Glib::ustring workProfile = params.icm.working; - Image8 *cropImgtrue; + // Computing the internal image for analysis, i.e. conversion from lab->Output profile (rtSettings.HistogramWorking disabled) or lab->WCS (rtSettings.HistogramWorking enabled) - if(settings->HistogramWorking) { - cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, workProfile, RI_RELATIVE, false); // HOMBRE: was RELATIVE by default in lab2rgb, is it safe to assume we have to use it again ? - } else { - if (params.icm.output == "" || params.icm.output == ColorManagementParams::NoICMString) { - outProfile = "sRGB"; - } - - cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, outProfile, params.icm.outputIntent, false); - } + // internal image in output color space for analysis + Image8 *cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, params.icm); int finalW = rqcropw; @@ -1121,7 +1111,7 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte PreviewProps cp (orx, ory, orw, orh, skip); int orW, orH; - parent->imgsrc->getSize (tr, cp, orW, orH); + parent->imgsrc->getSize (cp, orW, orH); int cw = SKIPS(bw, skip); int ch = SKIPS(bh, skip); diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index f1230bf01..450c659f0 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -44,7 +44,7 @@ protected: Imagefloat* origCrop; // "one chunk" allocation LabImage* laboCrop; // "one chunk" allocation LabImage* labnCrop; // "one chunk" allocation - Image8* cropImg; // "one chunk" allocation + Image8* cropImg; // "one chunk" allocation ; displayed image in monitor color space, showing the output profile as well (soft-proofing enabled, which then correspond to workimg) or not float * cbuf_real; // "one chunk" allocation SHMap* cshmap; // per line allocation diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index 347b96792..e0dea012b 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -36,16 +36,18 @@ extern const Settings* settings; inline dfInfo& dfInfo::operator =(const dfInfo &o) { - pathname = o.pathname; - maker = o.maker; - model = o.model; - iso = o.iso; - shutter = o.shutter; - timestamp = o.timestamp; + if (this != &o) { + pathname = o.pathname; + maker = o.maker; + model = o.model; + iso = o.iso; + shutter = o.shutter; + timestamp = o.timestamp; - if( ri ) { - delete ri; - ri = nullptr; + if( ri ) { + delete ri; + ri = NULL; + } } return *this; @@ -138,7 +140,7 @@ void dfInfo::updateRawImage() if( ri->loadRaw(true)) { delete ri; - ri = nullptr; + ri = NULL; } else { int H = ri->get_height(); int W = ri->get_width(); @@ -200,7 +202,7 @@ void dfInfo::updateRawImage() if( ri->loadRaw(true)) { delete ri; - ri = nullptr; + ri = NULL; } else { ri->compress_image(); } @@ -332,11 +334,11 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) auto file = Gio::File::create_for_path (filename); if (!file) { - return nullptr; + return 0; } if (!file->query_exists ()) { - return nullptr; + return 0; } try { @@ -344,11 +346,11 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) auto info = file->query_info (); if (!info && info->get_file_type () == Gio::FILE_TYPE_DIRECTORY) { - return nullptr; + return 0; } if (!options.fbShowHidden && info->is_hidden ()) { - return nullptr; + return 0; } Glib::ustring ext; @@ -359,14 +361,14 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) } if (!options.is_extention_enabled (ext)) { - return nullptr; + return 0; } RawImage ri (filename); int res = ri.loadRaw (false); // Read informations about shot if (res != 0) { - return nullptr; + return 0; } dfList_t::iterator iter; @@ -406,7 +408,7 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) } catch(Gio::Error&) {} - return nullptr; + return 0; } void DFManager::getStat( int &totFiles, int &totTemplates) @@ -433,7 +435,7 @@ void DFManager::getStat( int &totFiles, int &totTemplates) dfInfo* DFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ) { if( dfList.empty() ) { - return nullptr; + return 0; } std::string key( dfInfo::key(mak, mod, isospeed, shut) ); @@ -467,7 +469,7 @@ dfInfo* DFManager::find( const std::string &mak, const std::string &mod, int iso } } - return bestD != INFINITY ? &(bestMatch->second) : nullptr ; + return bestD != INFINITY ? &(bestMatch->second) : 0 ; } } @@ -478,7 +480,7 @@ RawImage* DFManager::searchDarkFrame( const std::string &mak, const std::string if( df ) { return df->getRawImage(); } else { - return nullptr; + return 0; } } @@ -496,7 +498,7 @@ RawImage* DFManager::searchDarkFrame( const Glib::ustring filename ) return df->getRawImage(); } - return nullptr; + return 0; } std::vector *DFManager::getHotPixels ( const Glib::ustring filename ) { @@ -506,7 +508,7 @@ std::vector *DFManager::getHotPixels ( const Glib::ustring filename ) } } - return nullptr; + return 0; } std::vector *DFManager::getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) { @@ -525,7 +527,7 @@ std::vector *DFManager::getHotPixels ( const std::string &mak, const std return &df->getHotPixels(); } else { - return nullptr; + return 0; } } @@ -624,7 +626,7 @@ std::vector *DFManager::getBadPixels ( const std::string &mak, const std } if(!found) { - return nullptr; + return 0; } else { return &(iter->second); } diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index a5505391e..2178e3dac 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -245,7 +245,7 @@ void DiagonalCurve::NURBS_set () printf("sc_length[%zu/3]=%f \n", it, sc_length[it / 3]); } - printf("NURBS diagonal curve: error detected!\n i=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f", i, nbr_points, ppn, N, sc_length[i / 3], total_length); + printf("NURBS diagonal curve: error detected!\n i=%u nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f", i, nbr_points, ppn, N, sc_length[i / 3], total_length); exit(0); } diff --git a/rtengine/ffmanager.cc b/rtengine/ffmanager.cc index eae00cad0..29121a696 100644 --- a/rtengine/ffmanager.cc +++ b/rtengine/ffmanager.cc @@ -31,17 +31,19 @@ extern const Settings* settings; inline ffInfo& ffInfo::operator =(const ffInfo &o) { - pathname = o.pathname; - maker = o.maker; - model = o.model; - lens = o.lens; - shutter = o.shutter; - focallength = o.focallength; - timestamp = o.timestamp; + if (this != &o) { + pathname = o.pathname; + maker = o.maker; + model = o.model; + lens = o.lens; + focallength = o.focallength; + timestamp = o.timestamp; + aperture = o.aperture; - if( ri ) { - delete ri; - ri = nullptr; + if( ri ) { + delete ri; + ri = NULL; + } } return *this; @@ -131,7 +133,7 @@ void ffInfo::updateRawImage() if( ri->loadRaw(true)) { delete ri; - ri = nullptr; + ri = NULL; } else { int H = ri->get_height(); int W = ri->get_width(); @@ -193,7 +195,7 @@ void ffInfo::updateRawImage() if( ri->loadRaw(true)) { delete ri; - ri = nullptr; + ri = NULL; } else { ri->compress_image(); } @@ -291,11 +293,11 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) auto file = Gio::File::create_for_path (filename); if (!file ) { - return nullptr; + return 0; } if (!file->query_exists ()) { - return nullptr; + return 0; } try { @@ -303,11 +305,11 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) auto info = file->query_info (); if (!info || info->get_file_type () == Gio::FILE_TYPE_DIRECTORY) { - return nullptr; + return 0; } if (!options.fbShowHidden && info->is_hidden ()) { - return nullptr; + return 0; } Glib::ustring ext; @@ -319,7 +321,7 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) } if (!options.is_extention_enabled (ext)) { - return nullptr; + return 0; } @@ -327,7 +329,7 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) int res = ri.loadRaw (false); // Read informations about shot if (res != 0) { - return nullptr; + return 0; } ffList_t::iterator iter; @@ -367,7 +369,7 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) } catch (Gio::Error&) {} - return nullptr; + return 0; } void FFManager::getStat( int &totFiles, int &totTemplates) @@ -394,7 +396,7 @@ void FFManager::getStat( int &totFiles, int &totTemplates) ffInfo* FFManager::find( const std::string &mak, const std::string &mod, const std::string &len, double focal, double apert, time_t t ) { if( ffList.empty() ) { - return nullptr; + return 0; } std::string key( ffInfo::key(mak, mod, len, focal, apert) ); @@ -428,7 +430,7 @@ ffInfo* FFManager::find( const std::string &mak, const std::string &mod, const s } } - return bestD != INFINITY ? &(bestMatch->second) : nullptr ; + return bestD != INFINITY ? &(bestMatch->second) : 0 ; } } @@ -439,7 +441,7 @@ RawImage* FFManager::searchFlatField( const std::string &mak, const std::string if( ff ) { return ff->getRawImage(); } else { - return nullptr; + return 0; } } @@ -457,7 +459,7 @@ RawImage* FFManager::searchFlatField( const Glib::ustring filename ) return ff->getRawImage(); } - return nullptr; + return 0; } diff --git a/rtengine/ffmanager.h b/rtengine/ffmanager.h index f285bb5bf..4a65c2ed7 100644 --- a/rtengine/ffmanager.h +++ b/rtengine/ffmanager.h @@ -34,8 +34,6 @@ public: std::string maker; ///< manufacturer std::string model; ///< model std::string lens; ///< lens - int iso; ///< ISO (gain) - double shutter; ///< shutter or exposure time in sec double aperture; ///< aperture in stops double focallength; ///< focal length in mm time_t timestamp; ///< seconds since 1 Jan 1970 diff --git a/rtengine/flatcurves.cc b/rtengine/flatcurves.cc index 5a4dfeacf..ae1a895ff 100644 --- a/rtengine/flatcurves.cc +++ b/rtengine/flatcurves.cc @@ -311,10 +311,10 @@ void FlatCurve::CtrlPoints_set () if (nbr_points < 0) { for(size_t it = 0; it < sc_x.size(); it += 3) { - printf("sc_length[%zd/3]=%f \n", it, sc_length[it / 3]); + printf("sc_length[%zu/3]=%f \n", it, sc_length[it / 3]); } - printf("Flat curve: error detected!\n i=%d k=%d periodic=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f\n", i, k, periodic, nbr_points, ppn, N, sc_length[i / 3], total_length); + printf("Flat curve: error detected!\n i=%u k=%u periodic=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f\n", i, k, periodic, nbr_points, ppn, N, sc_length[i / 3], total_length); exit(0); } diff --git a/rtengine/hlrecovery.cc b/rtengine/hlrecovery.cc deleted file mode 100644 index 4f527b660..000000000 --- a/rtengine/hlrecovery.cc +++ /dev/null @@ -1,397 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 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 . - */ - -namespace rtengine -{ - -template T** allocArray (int W, int H) -{ - - T** t = new T*[H]; - - for (int i = 0; i < H; i++) { - t[i] = new T[W]; - } - - return t; -} - -void RawImageSource::updateHLRecoveryMap (bool needred, bool needgreen, bool needblue, bool full) -{ - - // detect maximal pixel values - unsigned short* red = new unsigned short[W]; - unsigned short* blue = new unsigned short[W]; - int maxr = 0, maxg = 0, maxb = 0; - - for (int i = 32; i < H - 32; i++) { - interpolate_row_rb (red, blue, green[i - 1], green[i], green[i + 1], i); - - for (int j = 32; j < W - 32; j++) { - if (red[j] > maxr) { - maxr = red[j]; - } - - if (green[i][j] > maxg) { - maxg = green[i][j]; - } - - if (blue[j] > maxb) { - maxb = blue[j]; - } - } - } - - delete [] red; - delete [] blue; - - maxr = maxr * 19 / 20; - maxg = maxg * 19 / 20; - maxb = maxb * 19 / 20; - int max[3]; - max[0] = maxr; - max[1] = maxg; - max[2] = maxb; - - if( options.rtSettings.verbose ) { - printf ("HLRecoveryMap Maximum: R: %d, G: %d, B: %d\n", maxr, maxg, maxb); - } - - // downscale image - int dw = W / SCALE; - int dh = H / SCALE; - Image16* ds = new Image16 (dw, dh); - - // overburnt areas - int** rec[3]; - - for (int i = 0; i < 3; i++) { - rec[i] = allocArray (dw, dh); - } - - unsigned short* reds[SCALE]; - unsigned short* blues[SCALE]; - - for (int i = 0; i < SCALE; i++) { - reds[i] = new unsigned short[W]; - blues[i] = new unsigned short[W]; - } - - for (int i = 0; i < dh; i++) { - for (int j = 0; j < SCALE; j++) { - interpolate_row_rb (reds[j], blues[j], green[SCALE * i + j - 1], green[SCALE * i + j], green[SCALE * i + j + 1], SCALE * i + j); - } - - for (int j = 0; j < dw; j++) { - int sumr = 0; - int cr = 0; - int sumg = 0; - int cg = 0; - int sumb = 0; - int cb = 0; - - for (int x = 0; x < SCALE; x++) - for (int y = 0; y < SCALE; y++) { - int ix = SCALE * i + x; - int jy = SCALE * j + y; - sumr += reds[x][jy]; - - if (reds[x][jy] < maxr) { - cr++; - } - - sumg += green[ix][jy]; - - if (green[ix][jy] < maxg) { - cg++; - } - - sumb += blues[x][jy]; - - if (blues[x][jy] < maxb) { - cb++; - } - } - - if (cr < SCALE * SCALE && needred) { - rec[0][i][j] = INT_MAX; - } else { - rec[0][i][j] = sumr / SCALE / SCALE; - } - - if (cg < SCALE * SCALE && needgreen) { - rec[1][i][j] = INT_MAX; - } else { - rec[1][i][j] = sumg / SCALE / SCALE; - } - - if (cb < SCALE * SCALE && needblue) { - rec[2][i][j] = INT_MAX; - } else { - rec[2][i][j] = sumb / SCALE / SCALE; - } - - ds->r(i, j) = sumr / SCALE / SCALE; - ds->g(i, j) = sumg / SCALE / SCALE; - ds->b(i, j) = sumb / SCALE / SCALE; - } - } - - for (int i = 0; i < SCALE; i++) { - delete [] reds[i]; - delete [] blues[i]; - } - - - // STEP I. recover color from the partially lost areas - bool phase2 = false; - - for (int k = 0; k < 400; k++) { - if (k > 200) { - phase2 = true; - } - - for (int i = 1; i < dh - 1; i++) - for (int j = 1; j < dw - 1; j++) { - for (int c = 0; c < 3; c++) { - // if channel c is lost - if (rec[c][i][j] == INT_MAX) { - double ratio[2] = {0.0, 0.0}; - double w[2] = {0.0, 0.0}; - int count[2] = {0, 0}; - int ix = 0; - - for (int m = 0; m < 3; m++) { - if (m == c) { - continue; - } - - // if channel m is not lost at this point (or already recovered) - if (rec[m][i][j] != INT_MAX && rec[m][i][j] >= 0) { - for (int x = -1; x <= 1; x++) - for (int y = -1; y <= 1; y++) - - // average m/c color ratios in the surrounding pixels - if (rec[m][i + x][j + y] >= 0 && rec[m][i + x][j + y] != INT_MAX && rec[c][i + x][j + y] > 0 && rec[c][i + x][j + y] != INT_MAX) { - double ww = 1.0; - - if (!phase2 && (/*(double)(rec[m][i+x][j+y] - rec[m][i][j])/max[m]*(rec[m][i+x][j+y] - rec[m][i][j])/max[m] > 1.0/2 || */rec[c][i + x][j + y] < max[c] * 3 / 4)) { - continue; - } - - w[ix] += ww; - ratio[ix] += ww * rec[m][i + x][j + y] / rec[c][i + x][j + y]; - count[ix] ++; - } - } - - ix++; - } - - // compute new pixel values from the surrounding color ratios - double newc = 0.0; - int nc = 0; - ix = 0; - - for (int m = 0; m < 3; m++) { - if (c == m) { - continue; - } - - if (count[ix]) { - newc += (double)rec[m][i][j] / ratio[ix] * w[ix]; - nc++; - } - - ix++; - } - - if (nc) { - rec[c][i][j] = - (int) (newc / nc); - } - } - } - } - - bool change = false; - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) - for (int c = 0; c < 3; c++) { - if (rec[c][i][j] < 0) { - rec[c][i][j] = -rec[c][i][j]; - } - - change = true; - } - - if (!change) { - break; - } - } - - printf ("Phase1 vege\n"); - - // STEP II. recover fully lost pixels - if (full) { - int maxY = (299 * max[0] + 587 * max[1] + 114 * max[2]) / 1000; - phase2 = false; - - for (int k = 0; k < 600; k++) { - if (k > 200) { - phase2 = true; - } - - for (int i = 1; i < dh - 1; i++) - for (int j = 1; j < dw - 1; j++) { - if (rec[0][i][j] == INT_MAX || rec[1][i][j] == INT_MAX || rec[2][i][j] == INT_MAX) { - int count = 0; - double yavg = 0, iavg = 0, qavg = 0, weight = 0.0; - - for (int x = -1; x <= 1; x++) - for (int y = -1; y <= 1; y++) - if (rec[0][i + x][j + y] > 0 && rec[0][i + x][j + y] != INT_MAX && rec[1][i + x][j + y] > 0 && rec[1][i + x][j + y] != INT_MAX && rec[2][i + x][j + y] > 0 && rec[2][i + x][j + y] != INT_MAX) { - // convert to yiq - double Y = 0.299 * rec[0][i + x][j + y] + 0.587 * rec[1][i + x][j + y] + 0.114 * rec[2][i + x][j + y]; - double I = 0.596 * rec[0][i + x][j + y] - 0.275 * rec[1][i + x][j + y] - 0.321 * rec[2][i + x][j + y]; - double Q = 0.212 * rec[0][i + x][j + y] - 0.523 * rec[1][i + x][j + y] + 0.311 * rec[2][i + x][j + y]; - - if (Y > maxY * 7 / 10) { - double w = 1.0;// / (I*I+Q*Q); - yavg += Y * w; - iavg += I * w; - qavg += Q * w; - weight += w; - count++; - } - } - - if ((!phase2 && count > 5) || (phase2 && count > 3)) { - double Y = yavg / weight; - double I = iavg / weight; - double Q = qavg / weight; - rec[0][i][j] = - (Y + 0.956 * I + 0.621 * Q); - rec[1][i][j] = - (Y - 0.272 * I - 0.647 * Q); - rec[2][i][j] = - (Y - 1.105 * I + 1.702 * Q); - } - } - - } - - bool change = false; - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) - for (int c = 0; c < 3; c++) { - if (rec[c][i][j] < 0) { - rec[c][i][j] = -rec[c][i][j]; - } - - change = true; - } - - if (!change) { - break; - } - } - } - - int maxval = 0; - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) - for (int c = 0; c < 3; c++) - if (rec[c][i][j] != INT_MAX && rec[c][i][j] > maxval) { - maxval = rec[c][i][j]; - } - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) - if (rec[0][i][j] == INT_MAX || rec[1][i][j] == INT_MAX || rec[2][i][j] == INT_MAX) { - rec[0][i][j] = maxval; - rec[1][i][j] = maxval; - rec[2][i][j] = maxval; - } - - if (hrmap[0] != NULL) { - freeArray (hrmap[0], dh); - freeArray (hrmap[1], dh); - freeArray (hrmap[2], dh); - } - - hrmap[0] = allocArray (dw, dh); - hrmap[1] = allocArray (dw, dh); - hrmap[2] = allocArray (dw, dh); - - this->full = full; - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) { - hrmap[0][i][j] = (double)rec[0][i][j] / ds->r(i, j); - hrmap[1][i][j] = (double)rec[1][i][j] / ds->g(i, j); - hrmap[2][i][j] = (double)rec[2][i][j] / ds->b(i, j); - } - - /* for (int i=0; ir(i,j) = CLIP (rec[0][i][j]); - ds->g(i,j) = CLIP (rec[1][i][j]); - ds->b(i,j) = CLIP (rec[2][i][j]); - } - ds->save ("test.png"); - */ - delete ds; - freeArray (rec[0], dh); - freeArray (rec[1], dh); - freeArray (rec[2], dh); - - printf ("HLMap vege\n"); -} - -void RawImageSource::hlRecovery (unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int sx2, int skip) -{ - - int blr = (i + SCALE / 2) / SCALE - 1; - - if (blr < 0 || blr >= H / SCALE - 1) { - return; - } - - double mr1 = 1.0 - ((double)((i + SCALE / 2) % SCALE) / SCALE + 0.5 / SCALE); - int jx = 0; - int maxcol = W / SCALE; - - for (int j = sx1, jx = 0; j < sx2; j += skip, jx++) { - int blc = (j + SCALE / 2) / SCALE - 1; - - if (blc < 0 || blc >= maxcol - 1) { - continue; - } - - double mc1 = 1.0 - ((double)((j + SCALE / 2) % SCALE) / SCALE + 0.5 / SCALE); - double mulr = mr1 * mc1 * hrmap[0][blr][blc] + mr1 * (1.0 - mc1) * hrmap[0][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[0][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[0][blr + 1][blc + 1]; - double mulg = mr1 * mc1 * hrmap[1][blr][blc] + mr1 * (1.0 - mc1) * hrmap[1][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[1][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[1][blr + 1][blc + 1]; - double mulb = mr1 * mc1 * hrmap[2][blr][blc] + mr1 * (1.0 - mc1) * hrmap[2][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[2][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[2][blr + 1][blc + 1]; - red[jx] = CLIP(red[jx] * mulr); - green[jx] = CLIP(green[jx] * mulg); - blue[jx] = CLIP(blue[jx] * mulb); - } -} -} - diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 85409fd53..7b52a7a53 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -32,14 +32,15 @@ #include "../rtgui/options.h" -namespace +namespace rtengine { +extern const Settings* settings; void loadProfiles (const Glib::ustring& dirName, std::map* profiles, - std::map* profileContents, + std::map* profileContents, std::map* profileNames, - bool nameUpper, bool onlyRgb) + bool nameUpper) { if (dirName.empty ()) { return; @@ -76,10 +77,10 @@ void loadProfiles (const Glib::ustring& dirName, } if (profiles) { - const rtengine::ProfileContent content (filePath); + const ProfileContent content (filePath); const cmsHPROFILE profile = content.toProfile (); - if (profile && (!onlyRgb || cmsGetColorSpace (profile) == cmsSigRgbData)) { + if (profile) { profiles->insert (std::make_pair (name, profile)); if (profileContents) { @@ -95,20 +96,20 @@ void loadProfiles (const Glib::ustring& dirName, } catch (Glib::Exception&) {} } -inline void getSupportedIntent (cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, std::uint8_t& result) +inline void getSupportedIntent (cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, uint8_t& result) { if (cmsIsIntentSupported (profile, intent, direction)) { result |= 1 << intent; } } -inline std::uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number direction) +inline uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number direction) { if (!profile) { return 0; } - std::uint8_t result = 0; + uint8_t result = 0; getSupportedIntent (profile, INTENT_PERCEPTUAL, direction, result); getSupportedIntent (profile, INTENT_RELATIVE_COLORIMETRIC, direction, result); @@ -121,7 +122,7 @@ inline std::uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number di inline cmsHPROFILE createXYZProfile () { double mat[3][3] = { {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0} }; - return rtengine::ICCStore::createFromMatrix (mat, false, "XYZ"); + return ICCStore::createFromMatrix (mat, false, "XYZ"); } const double (*wprofiles[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best, xyz_rec2020}; @@ -164,7 +165,7 @@ std::vector getWorkingProfiles () return res; } -std::vector ICCStore::getProfiles () const +std::vector ICCStore::getProfiles (const bool onlyRgb) const { MyMutex::MyLock lock(mutex_); @@ -172,6 +173,7 @@ std::vector ICCStore::getProfiles () const std::vector res; for (ProfileMap::const_iterator profile = fileProfiles.begin (); profile != fileProfiles.end (); ++profile) { + if (!onlyRgb || (onlyRgb && cmsGetColorSpace (profile->second) == cmsSigRgbData)) res.push_back (profile->first); } @@ -187,8 +189,8 @@ std::vector ICCStore::getProfilesFromDir (const Glib::ustring& di ProfileMap profiles; - loadProfiles (profilesDir, &profiles, nullptr, nullptr, false, true); - loadProfiles (dirName, &profiles, nullptr, nullptr, false, true); + loadProfiles (profilesDir, &profiles, nullptr, nullptr, false); + loadProfiles (dirName, &profiles, nullptr, nullptr, false); for (ProfileMap::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) { res.push_back (profile->first); @@ -205,7 +207,7 @@ cmsHPROFILE ICCStore::makeStdGammaProfile (cmsHPROFILE iprof) } cmsUInt32Number bytesNeeded = 0; - cmsSaveProfileToMem(iprof, nullptr, &bytesNeeded); + cmsSaveProfileToMem(iprof, 0, &bytesNeeded); if (bytesNeeded == 0) { return nullptr; @@ -362,6 +364,312 @@ cmsHPROFILE ICCStore::workingSpaceGamma (const Glib::ustring& name) const } } +void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &ga) +{ + const double eps = 0.000000001; // not divide by zero + if (!icm.freegamma) {//if Free gamma not selected + // gamma : ga[0],ga[1],ga[2],ga[3],ga[4],ga[5] by calcul + if(icm.gamma == "BT709_g2.2_s4.5") { + ga[0] = 2.22; //BT709 2.2 4.5 - my preferred as D.Coffin + ga[1] = 0.909995; + ga[2] = 0.090005; + ga[3] = 0.222222; + ga[4] = 0.081071; + } else if (icm.gamma == "sRGB_g2.4_s12.92") { + ga[0] = 2.40; //sRGB 2.4 12.92 - RT default as Lightroom + ga[1] = 0.947858; + ga[2] = 0.052142; + ga[3] = 0.077399; + ga[4] = 0.039293; + } else if (icm.gamma == "High_g1.3_s3.35") { + ga[0] = 1.3 ; //for high dynamic images + ga[1] = 0.998279; + ga[2] = 0.001721; + ga[3] = 0.298507; + ga[4] = 0.005746; + } else if (icm.gamma == "Low_g2.6_s6.9") { + ga[0] = 2.6 ; //gamma 2.6 variable : for low contrast images + ga[1] = 0.891161; + ga[2] = 0.108839; + ga[3] = 0.144928; + ga[4] = 0.076332; + } else if (icm.gamma == "standard_g2.2") { + ga[0] = 2.2; //gamma=2.2 (as gamma of Adobe, Widegamut...) + ga[1] = 1.; + ga[2] = 0.; + ga[3] = 1. / eps; + ga[4] = 0.; + } else if (icm.gamma == "standard_g1.8") { + ga[0] = 1.8; //gamma=1.8 (as gamma of Prophoto) + ga[1] = 1.; + ga[2] = 0.; + ga[3] = 1. / eps; + ga[4] = 0.; + } else /* if (icm.gamma == "linear_g1.0") */ { + ga[0] = 1.0; //gamma=1 linear : for high dynamic images (cf : D.Coffin...) + ga[1] = 1.; + ga[2] = 0.; + ga[3] = 1. / eps; + ga[4] = 0.; + } + ga[5] = 0.0; + ga[6] = 0.0; + } else { //free gamma selected + GammaValues g_a; //gamma parameters + double pwr = 1.0 / icm.gampos; + double ts = icm.slpos; + double slope = icm.slpos == 0 ? eps : icm.slpos; + + int mode = 0, imax = 0; + Color::calcGamma(pwr, ts, mode, imax, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 + ga[4] = g_a[3] * ts; + //printf("g_a.gamma0=%f g_a.gamma1=%f g_a.gamma2=%f g_a.gamma3=%f g_a.gamma4=%f\n", g_a.gamma0,g_a.gamma1,g_a.gamma2,g_a.gamma3,g_a.gamma4); + ga[0] = icm.gampos; + ga[1] = 1. / (1.0 + g_a[4]); + ga[2] = g_a[4] / (1.0 + g_a[4]); + ga[3] = 1. / slope; + ga[5] = 0.0; + ga[6] = 0.0; + //printf("ga[0]=%f ga[1]=%f ga[2]=%f ga[3]=%f ga[4]=%f\n", ga[0],ga[1],ga[2],ga[3],ga[4]); + } +} + +// WARNING: the caller must lock lcmsMutex +cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParams &icm, GammaValues &ga) { + float p[6]; //primaries + ga[6] = 0.0; + + enum class ColorTemp { + D50 = 5003, // for Widegamut, Prophoto Best, Beta -> D50 + D65 = 6504 // for sRGB, AdobeRGB, Bruce Rec2020 -> D65 + }; + ColorTemp temp = ColorTemp::D50; + + //primaries for 7 working profiles ==> output profiles + // eventually to adapt primaries if RT used special profiles ! + if (icm.output == "WideGamut") { + p[0] = 0.7350; //Widegamut primaries + p[1] = 0.2650; + p[2] = 0.1150; + p[3] = 0.8260; + p[4] = 0.1570; + p[5] = 0.0180; + } else if (icm.output == "Adobe RGB") { + p[0] = 0.6400; //Adobe primaries + p[1] = 0.3300; + p[2] = 0.2100; + p[3] = 0.7100; + p[4] = 0.1500; + p[5] = 0.0600; + temp = ColorTemp::D65; + } else if (icm.output == "sRGB") { + p[0] = 0.6400; // sRGB primaries + p[1] = 0.3300; + p[2] = 0.3000; + p[3] = 0.6000; + p[4] = 0.1500; + p[5] = 0.0600; + temp = ColorTemp::D65; + } else if (icm.output == "BruceRGB") { + p[0] = 0.6400; // Bruce primaries + p[1] = 0.3300; + p[2] = 0.2800; + p[3] = 0.6500; + p[4] = 0.1500; + p[5] = 0.0600; + temp = ColorTemp::D65; + } else if (icm.output == "Beta RGB") { + p[0] = 0.6888; // Beta primaries + p[1] = 0.3112; + p[2] = 0.1986; + p[3] = 0.7551; + p[4] = 0.1265; + p[5] = 0.0352; + } else if (icm.output == "BestRGB") { + p[0] = 0.7347; // Best primaries + p[1] = 0.2653; + p[2] = 0.2150; + p[3] = 0.7750; + p[4] = 0.1300; + p[5] = 0.0350; + } else if (icm.output == "Rec2020") { + p[0] = 0.7080; // Rec2020 primaries + p[1] = 0.2920; + p[2] = 0.1700; + p[3] = 0.7970; + p[4] = 0.1310; + p[5] = 0.0460; + temp = ColorTemp::D65; + } else { + p[0] = 0.7347; //ProPhoto and default primaries + p[1] = 0.2653; + p[2] = 0.1596; + p[3] = 0.8404; + p[4] = 0.0366; + p[5] = 0.0001; + } + + cmsCIExyY xyD; + cmsCIExyYTRIPLE Primaries = { + {p[0], p[1], 1.0}, // red + {p[2], p[3], 1.0}, // green + {p[4], p[5], 1.0} // blue + }; + cmsToneCurve* GammaTRC[3]; + + // 7 parameters for smoother curves + cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] } ; + + //lcmsMutex->lock (); Mutex acquired by the caller + cmsWhitePointFromTemp(&xyD, (double)temp); + GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters); //5 = smoother than 4 + cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); //oprofdef become Outputprofile + cmsFreeToneCurve(GammaTRC[0]); + //lcmsMutex->unlock (); + + return oprofdef; +} + +// WARNING: the caller must lock lcmsMutex +cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, GammaValues &ga) { + bool pro = false; + Glib::ustring outProfile; + cmsHPROFILE outputProfile = nullptr; + + if (icm.freegamma && icm.gampos < 1.35) { + pro = true; //select profil with gammaTRC modified : + } else if (icm.gamma == "linear_g1.0" || (icm.gamma == "High_g1.3_s3.35")) { + pro = true; //pro=0 RT_sRGB || Prophoto + } + + // Check that output profiles exist, otherwise use LCMS2 + // Use the icc/icm profiles associated to possible working profiles, set in "options" + if (icm.working == "ProPhoto" && iccStore->outputProfileExist(options.rtSettings.prophoto) && !pro) { + outProfile = options.rtSettings.prophoto; + } else if (icm.working == "Adobe RGB" && iccStore->outputProfileExist(options.rtSettings.adobe) ) { + outProfile = options.rtSettings.adobe; + } else if (icm.working == "WideGamut" && iccStore->outputProfileExist(options.rtSettings.widegamut) ) { + outProfile = options.rtSettings.widegamut; + } else if (icm.working == "Beta RGB" && iccStore->outputProfileExist(options.rtSettings.beta) ) { + outProfile = options.rtSettings.beta; + } else if (icm.working == "BestRGB" && iccStore->outputProfileExist(options.rtSettings.best) ) { + outProfile = options.rtSettings.best; + } else if (icm.working == "BruceRGB" && iccStore->outputProfileExist(options.rtSettings.bruce) ) { + outProfile = options.rtSettings.bruce; + } else if (icm.working == "sRGB" && iccStore->outputProfileExist(options.rtSettings.srgb) && !pro) { + outProfile = options.rtSettings.srgb; + } else if (icm.working == "sRGB" && iccStore->outputProfileExist(options.rtSettings.srgb10) && pro) { + outProfile = options.rtSettings.srgb10; + } else if (icm.working == "ProPhoto" && iccStore->outputProfileExist(options.rtSettings.prophoto10) && pro) { + outProfile = options.rtSettings.prophoto10; + } else if (icm.working == "Rec2020" && iccStore->outputProfileExist(options.rtSettings.rec2020) ) { + outProfile = options.rtSettings.rec2020; + } else { + // Should not occurs + if (settings->verbose) { + printf("\"%s\": unknown working profile! - use LCMS2 substitution\n", icm.working.c_str() ); + } + + return nullptr; + } + + //begin adaptation rTRC gTRC bTRC + //"outputProfile" profile has the same characteristics than RGB values, but TRC are adapted... for applying profile + if (settings->verbose) { + printf("Output Gamma - profile: \"%s\"\n", outProfile.c_str() ); //c_str() + } + + outputProfile = iccStore->getProfile(outProfile); //get output profile + + if (outputProfile == nullptr) { + + if (settings->verbose) { + printf("\"%s\" ICC output profile not found!\n", outProfile.c_str()); + } + return nullptr; + } + + // 7 parameters for smoother curves + cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] }; + + //change desc Tag , to "free gamma", or "BT709", etc. + cmsMLU *mlu; + cmsContext ContextID = cmsGetProfileContextID(outputProfile); // create context to modify some TAGs + mlu = cmsMLUalloc(ContextID, 1); + + // instruction with //ICC are used to generate ICC profile + if (mlu == nullptr) { + printf("Description error\n"); + } else { + + // Description TAG : selection of gamma and Primaries + if (!icm.freegamma) { + std::wstring gammaStr; + + if(icm.gamma == "High_g1.3_s3.35") { + gammaStr = std::wstring(L"GammaTRC: High g=1.3 s=3.35"); + } else if (icm.gamma == "Low_g2.6_s6.9") { + gammaStr = std::wstring(L"GammaTRC: Low g=2.6 s=6.9"); + } else if (icm.gamma == "sRGB_g2.4_s12.92") { + gammaStr = std::wstring(L"GammaTRC: sRGB g=2.4 s=12.92"); + } else if (icm.gamma == "BT709_g2.2_s4.5") { + gammaStr = std::wstring(L"GammaTRC: BT709 g=2.2 s=4.5"); + } else if (icm.gamma == "linear_g1.0") { + gammaStr = std::wstring(L"GammaTRC: Linear g=1.0"); + } else if (icm.gamma == "standard_g2.2") { + gammaStr = std::wstring(L"GammaTRC: g=2.2"); + } else if (icm.gamma == "standard_g1.8") { + gammaStr = std::wstring(L"GammaTRC: g=1.8"); + } + + cmsMLUsetWide(mlu, "en", "US", gammaStr.c_str()); + } else { + // create description with gamma + slope + primaries + std::wostringstream gammaWs; + gammaWs.precision(2); + gammaWs << "Manual GammaTRC: g=" << (float)icm.gampos << " s=" << (float)icm.slpos; + + cmsMLUsetWide(mlu, "en", "US", gammaWs.str().c_str()); + } + + cmsWriteTag(outputProfile, cmsSigProfileDescriptionTag, mlu);//desc changed + + /* + cmsMLUsetWide(mlu, "en", "US", L"General Public License - AdobeRGB compatible");//adapt to profil + cmsWriteTag(outputProfile, cmsSigCopyrightTag, mlu); + + cmsMLUsetWide(mlu, "en", "US", L"RawTherapee"); + cmsWriteTag(outputProfile, cmsSigDeviceMfgDescTag, mlu); + + cmsMLUsetWide(mlu, "en", "US", L"RTMedium"); //adapt to profil + cmsWriteTag(outputProfile, cmsSigDeviceModelDescTag, mlu); + + */ + + cmsMLUfree (mlu); + } + + // Calculate output profile's rTRC gTRC bTRC + cmsToneCurve* GammaTRC = nullptr; + GammaTRC = cmsBuildParametricToneCurve(nullptr, 5, Parameters); + cmsWriteTag(outputProfile, cmsSigRedTRCTag, (void*)GammaTRC ); + cmsWriteTag(outputProfile, cmsSigGreenTRCTag, (void*)GammaTRC ); + cmsWriteTag(outputProfile, cmsSigBlueTRCTag, (void*)GammaTRC ); + + if (GammaTRC) { + cmsFreeToneCurve(GammaTRC); + } + + return outputProfile; +} + +bool ICCStore::outputProfileExist (const Glib::ustring& name) const +{ + + MyMutex::MyLock lock(mutex_); + return fileProfiles.find(name) != fileProfiles.end(); +} + cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) const { @@ -433,21 +741,21 @@ ProfileContent ICCStore::getContent (const Glib::ustring& name) const return r != fileProfileContents.end () ? r->second : ProfileContent(); } -std::uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) const { MyMutex::MyLock lock (mutex_); return getSupportedIntents (profile, LCMS_USED_AS_INPUT); } -std::uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) const { MyMutex::MyLock lock (mutex_); return getSupportedIntents (profile, LCMS_USED_AS_OUTPUT); } -std::uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) const { MyMutex::MyLock lock (mutex_); @@ -464,15 +772,15 @@ void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCD profilesDir = Glib::build_filename (rtICCDir, "output"); fileProfiles.clear(); fileProfileContents.clear(); - loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false, true); - loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, nullptr, false, true); + loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false); + loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, nullptr, false); // Input profiles // Load these to different areas, since the short name (e.g. "NIKON D700" may overlap between system/user and RT dir) stdProfilesDir = Glib::build_filename (rtICCDir, "input"); fileStdProfiles.clear(); fileStdProfilesFileNames.clear(); - loadProfiles (stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true, false); + loadProfiles (stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true); } // Determine the first monitor default profile of operating system, if selected @@ -551,7 +859,7 @@ ProfileContent::ProfileContent (cmsHPROFILE hProfile) : data(nullptr), length(0) if (hProfile != nullptr) { cmsUInt32Number bytesNeeded = 0; - cmsSaveProfileToMem(hProfile, nullptr, &bytesNeeded); + cmsSaveProfileToMem(hProfile, 0, &bytesNeeded); if (bytesNeeded > 0) { data = new char[bytesNeeded + 1]; diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 62212e397..bb9693f1a 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -23,6 +23,9 @@ #include #include #include +#include +#include "procparams.h" +#include "color.h" #include "../rtgui/threadutils.h" namespace rtengine @@ -85,8 +88,11 @@ public: void init (const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir); + static void getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &ga); static cmsHPROFILE makeStdGammaProfile (cmsHPROFILE iprof); static cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma = false, const Glib::ustring& name = Glib::ustring()); + static cmsHPROFILE createGammaProfile (const procparams::ColorManagementParams &icm, GammaValues &ga); + static cmsHPROFILE createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, GammaValues &ga); // Main monitors standard profile name, from OS void findDefaultMonitorProfile (); @@ -98,23 +104,24 @@ public: TMatrix workingSpaceMatrix (const Glib::ustring& name) const; TMatrix workingSpaceInverseMatrix (const Glib::ustring& name) const; - cmsHPROFILE getProfile (const Glib::ustring& name) const; - cmsHPROFILE getStdProfile (const Glib::ustring& name) const; - ProfileContent getContent (const Glib::ustring& name) const; + bool outputProfileExist (const Glib::ustring& name) const; + cmsHPROFILE getProfile (const Glib::ustring& name) const; + cmsHPROFILE getStdProfile (const Glib::ustring& name) const; + ProfileContent getContent (const Glib::ustring& name) const; cmsHPROFILE getXYZProfile () const; cmsHPROFILE getsRGBProfile () const; - std::vector getProfiles () const; + std::vector getProfiles (const bool onlyRgb = false) const; std::vector getProfilesFromDir (const Glib::ustring& dirName) const; - std::uint8_t getInputIntents (cmsHPROFILE profile) const; - std::uint8_t getOutputIntents (cmsHPROFILE profile) const; - std::uint8_t getProofIntents (cmsHPROFILE profile) const; + uint8_t getInputIntents (cmsHPROFILE profile) const; + uint8_t getOutputIntents (cmsHPROFILE profile) const; + uint8_t getProofIntents (cmsHPROFILE profile) const; - std::uint8_t getInputIntents (const Glib::ustring& name) const; - std::uint8_t getOutputIntents (const Glib::ustring& name) const; - std::uint8_t getProofIntents (const Glib::ustring& name) const; + uint8_t getInputIntents (const Glib::ustring& name) const; + uint8_t getOutputIntents (const Glib::ustring& name) const; + uint8_t getProofIntents (const Glib::ustring& name) const; }; #define iccStore ICCStore::getInstance() @@ -140,17 +147,17 @@ inline Glib::ustring ICCStore::getDefaultMonitorProfileName () const return defaultMonitorProfile; } -inline std::uint8_t ICCStore::getInputIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getInputIntents (const Glib::ustring &name) const { return getInputIntents (getProfile (name)); } -inline std::uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) const { return getOutputIntents (getProfile (name)); } -inline std::uint8_t ICCStore::getProofIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getProofIntents (const Glib::ustring &name) const { return getProofIntents (getProfile (name)); } diff --git a/rtengine/image16.cc b/rtengine/image16.cc index b61170e03..df2c5a21f 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -326,43 +326,48 @@ Image16::tofloat() } // Parallized transformation; create transform with cmsFLAGS_NOCACHE! -void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform) +void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy) { - //cmsDoTransform(hTransform, data, data, planestride); - - // LittleCMS cannot parallelize planar setups -- Hombre: LCMS2.4 can! But it we use this new feature, memory allocation have to be modified too + // LittleCMS cannot parallelize planar Lab float images // so build temporary buffers to allow multi processor execution #ifdef _OPENMP #pragma omp parallel #endif { - AlignedBuffer buffer(width * 3); + AlignedBuffer bufferLab(width * 3); + AlignedBuffer bufferRGB(width * 3); #ifdef _OPENMP #pragma omp for schedule(static) #endif - for (int y = 0; y < height; y++) + for (int y = cy; y < cy + height; y++) { - unsigned short *p = buffer.data, *pR = r(y), *pG = g(y), *pB = b(y); + unsigned short *pRGB, *pR, *pG, *pB; + float *pLab, *pL, *pa, *pb; + + pLab= bufferLab.data; + pL = labImage.L[y] + cx; + pa = labImage.a[y] + cx; + pb = labImage.b[y] + cx; for (int x = 0; x < width; x++) { - *(p++) = *(pR++); - *(p++) = *(pG++); - *(p++) = *(pB++); + *(pLab++) = *(pL++) / 327.68f; + *(pLab++) = *(pa++) / 327.68f; + *(pLab++) = *(pb++) / 327.68f; } - cmsDoTransform (hTransform, buffer.data, buffer.data, width); + cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width); - p = buffer.data; - pR = r(y); - pG = g(y); - pB = b(y); + pRGB = bufferRGB.data; + pR = r(y - cy); + pG = g(y - cy); + pB = b(y - cy); for (int x = 0; x < width; x++) { - *(pR++) = *(p++); - *(pG++) = *(p++); - *(pB++) = *(p++); + *(pR++) = *(pRGB++); + *(pG++) = *(pRGB++); + *(pB++) = *(pRGB++); } } // End of parallelization } diff --git a/rtengine/image16.h b/rtengine/image16.h index 05357839c..0612dc614 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -96,7 +96,7 @@ public: delete this; } - void ExecCMSTransform(cmsHTRANSFORM hTransform); + void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy); }; } diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 0b3d17905..48d9d81b6 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -52,7 +52,7 @@ namespace // Opens a file for binary writing and request exclusive lock (cases were you need "wb" mode plus locking) FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname) { - FILE* f = nullptr; + FILE* f = NULL; #ifdef WIN32 @@ -91,13 +91,13 @@ Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid h // For only copying the raw input data void ImageIO::setMetadata (const rtexif::TagDirectory* eroot) { - if (exifRoot != nullptr) { + if (exifRoot != NULL) { delete exifRoot; - exifRoot = nullptr; + exifRoot = NULL; } if (eroot) { - rtexif::TagDirectory* td = ((rtexif::TagDirectory*)eroot)->clone (nullptr); + rtexif::TagDirectory* td = ((rtexif::TagDirectory*)eroot)->clone (NULL); // make IPTC and XMP pass through td->keepTag(0x83bb); // IPTC @@ -115,18 +115,18 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr exifChange.clear(); exifChange = exif; - if (exifRoot != nullptr) { + if (exifRoot != NULL) { delete exifRoot; - exifRoot = nullptr; + exifRoot = NULL; } if (eroot) { - exifRoot = ((rtexif::TagDirectory*)eroot)->clone (nullptr); + exifRoot = ((rtexif::TagDirectory*)eroot)->clone (NULL); } - if (iptc != nullptr) { + if (iptc != NULL) { iptc_data_free (iptc); - iptc = nullptr; + iptc = NULL; } // build iptc structures for libiptcdata @@ -184,7 +184,7 @@ void ImageIO::setOutputProfile (char* pdata, int plen) profileData = new char [plen]; memcpy (profileData, pdata, plen); } else { - profileData = nullptr; + profileData = NULL; } profileLength = plen; @@ -224,7 +224,7 @@ int ImageIO::getPNGSampleFormat (Glib::ustring fname, IIOSampleFormat &sFormat, } //initializing main structures - png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png) { fclose (file); @@ -303,7 +303,7 @@ int ImageIO::loadPNG (Glib::ustring fname) } //initializing main structures - png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png) { fclose (file); @@ -331,7 +331,7 @@ int ImageIO::loadPNG (Glib::ustring fname) png_read_info(png, info); - embProfile = nullptr; + embProfile = NULL; //retrieving image information png_uint_32 width, height; @@ -388,7 +388,7 @@ int ImageIO::loadPNG (Glib::ustring fname) for (unsigned int i = 0; i < height; i++) { - png_read_row (png, (png_byte*)row, nullptr); + png_read_row (png, (png_byte*)row, NULL); if (bit_depth == 16) { // convert scanline to host byte order unsigned short* srow = (unsigned short*)row; @@ -405,7 +405,7 @@ int ImageIO::loadPNG (Glib::ustring fname) } } - png_read_end (png, nullptr); + png_read_end (png, 0); png_destroy_read_struct (&png, &info, &end_info); delete [] row; @@ -489,7 +489,7 @@ int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize) if (hasprofile) { embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); } else { - embProfile = nullptr; + embProfile = NULL; } jpeg_start_decompress(&cinfo); @@ -568,7 +568,7 @@ int ImageIO::loadJPEG (Glib::ustring fname) if (hasprofile) { embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); } else { - embProfile = nullptr; + embProfile = NULL; } jpeg_start_decompress(&cinfo); @@ -623,7 +623,7 @@ int ImageIO::getTIFFSampleFormat (Glib::ustring fname, IIOSampleFormat &sFormat, TIFF* in = TIFFOpen(fname.c_str(), "r"); #endif - if (in == nullptr) { + if (in == NULL) { return IMIO_CANNOTREADFILE; } @@ -732,7 +732,7 @@ int ImageIO::loadTIFF (Glib::ustring fname) TIFF* in = TIFFOpen(fname.c_str(), "r"); #endif - if (in == nullptr) { + if (in == NULL) { return IMIO_CANNOTREADFILE; } @@ -771,39 +771,39 @@ int ImageIO::loadTIFF (Glib::ustring fname) * We could use the min/max values set in TIFFTAG_SMINSAMPLEVALUE and * TIFFTAG_SMAXSAMPLEVALUE, but for now, we normalize the image to the * effective minimum and maximum values - * - printf("Informations de \"%s\":\n", fname.c_str()); - uint16 tiffDefaultScale, tiffBaselineExposure, tiffLinearResponseLimit; - if (TIFFGetField(in, TIFFTAG_DEFAULTSCALE, &tiffDefaultScale)) { - printf(" DefaultScale: %d\n", tiffDefaultScale); - } - else - printf(" No DefaultScale value!\n"); - if (TIFFGetField(in, TIFFTAG_BASELINEEXPOSURE, &tiffBaselineExposure)) { - printf(" BaselineExposure: %d\n", tiffBaselineExposure); - } - else - printf(" No BaselineExposure value!\n"); - if (TIFFGetField(in, TIFFTAG_LINEARRESPONSELIMIT, &tiffLinearResponseLimit)) { - printf(" LinearResponseLimit: %d\n", tiffLinearResponseLimit); - } - else - printf(" No LinearResponseLimit value!\n"); + */ + if (options.rtSettings.verbose) { + printf("Informations of \"%s\":\n", fname.c_str()); + uint16 tiffDefaultScale, tiffBaselineExposure, tiffLinearResponseLimit; + if (TIFFGetField(in, TIFFTAG_DEFAULTSCALE, &tiffDefaultScale)) { + printf(" DefaultScale: %d\n", tiffDefaultScale); + } + else + printf(" No DefaultScale value!\n"); + if (TIFFGetField(in, TIFFTAG_BASELINEEXPOSURE, &tiffBaselineExposure)) { + printf(" BaselineExposure: %d\n", tiffBaselineExposure); + } + else + printf(" No BaselineExposure value!\n"); + if (TIFFGetField(in, TIFFTAG_LINEARRESPONSELIMIT, &tiffLinearResponseLimit)) { + printf(" LinearResponseLimit: %d\n", tiffLinearResponseLimit); + } + else + printf(" No LinearResponseLimit value!\n"); - uint16 tiffMinValue, tiffMaxValue; - if (TIFFGetField(in, TIFFTAG_SMINSAMPLEVALUE, &tiffMinValue)) { - printf(" MinValue: %d\n", tiffMinValue); + uint16 tiffMinValue, tiffMaxValue; + if (TIFFGetField(in, TIFFTAG_SMINSAMPLEVALUE, &tiffMinValue)) { + printf(" MinValue: %d\n", tiffMinValue); + } + else + printf(" No minimum value!\n"); + if (TIFFGetField(in, TIFFTAG_SMAXSAMPLEVALUE, &tiffMaxValue)) { + printf(" MaxValue: %d\n\n", tiffMaxValue); + } + else + printf(" No maximum value!\n\n"); + printf(" Those values are not taken into account, the image data are normalized to a [0;1] range\n\n"); } - else - printf(" No minimum value!\n"); - if (TIFFGetField(in, TIFFTAG_SMAXSAMPLEVALUE, &tiffMaxValue)) { - printf(" MaxValue: %d\n\n", tiffMaxValue); - } - else - printf(" No maximum value!\n\n"); - printf("\n"); - */ - char* profdata; deleteLoadedProfileData(); @@ -811,32 +811,10 @@ int ImageIO::loadTIFF (Glib::ustring fname) if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &loadedProfileLength, &profdata)) { embProfile = cmsOpenProfileFromMem (profdata, loadedProfileLength); - - // For 32 bits floating point images, gamma is forced to linear in embedded ICC profiles - if ( sampleFormat & (IIOSF_LOGLUV24 | IIOSF_LOGLUV32 | IIOSF_FLOAT) ) { - // Modifying the gammaTRG tags - cmsWriteTag(embProfile, cmsSigGreenTRCTag, (void*)Color::linearGammaTRC ); - cmsWriteTag(embProfile, cmsSigRedTRCTag, (void*)Color::linearGammaTRC ); - cmsWriteTag(embProfile, cmsSigBlueTRCTag, (void*)Color::linearGammaTRC ); - - // Saving the profile in the memory - cmsUInt32Number bytesNeeded = 0; - cmsSaveProfileToMem(embProfile, nullptr, &bytesNeeded); - - if (bytesNeeded > 0) { - loadedProfileData = new char[bytesNeeded + 1]; - cmsSaveProfileToMem(embProfile, loadedProfileData, &bytesNeeded); - } - - loadedProfileLength = (int)bytesNeeded; - } else { - // Saving the profile in the memory as is - loadedProfileData = new char [loadedProfileLength]; - memcpy (loadedProfileData, profdata, loadedProfileLength); - } - + loadedProfileData = new char [loadedProfileLength]; + memcpy (loadedProfileData, profdata, loadedProfileLength); } else { - embProfile = nullptr; + embProfile = NULL; } allocate (width, height); @@ -859,7 +837,7 @@ int ImageIO::loadTIFF (Glib::ustring fname) if (sampleFormat & (IIOSF_LOGLUV24 | IIOSF_LOGLUV32 | IIOSF_FLOAT)) { setScanline (row, linebuffer, bitspersample, minValue, maxValue); } else { - setScanline (row, linebuffer, bitspersample, nullptr, nullptr); + setScanline (row, linebuffer, bitspersample, NULL, NULL); } if (pl && !(row % 100)) { @@ -930,7 +908,7 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) pl->setProgress (0.0); } - png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png) { fclose (file); @@ -940,7 +918,7 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) png_infop info = png_create_info_struct(png); if (!info) { - png_destroy_write_struct (&png, nullptr); + png_destroy_write_struct (&png, 0); fclose (file); return IMIO_HEADERERROR; } @@ -1123,7 +1101,7 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) int bytes = 0; - if (!error && (bytes = iptc_jpeg_ps3_save_iptc (nullptr, 0, iptcdata, size, buffer, 65532)) < 0) { + if (!error && (bytes = iptc_jpeg_ps3_save_iptc (NULL, 0, iptcdata, size, buffer, 65532)) < 0) { if (iptcdata) { iptc_data_free_buf (iptc, iptcdata); } @@ -1329,23 +1307,23 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) //TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed. - if ((tag = exifRoot->getTag (TIFFTAG_MODEL)) != nullptr) { + if ((tag = exifRoot->getTag (TIFFTAG_MODEL)) != NULL) { TIFFSetField (out, TIFFTAG_MODEL, tag->getValue()); } - if ((tag = exifRoot->getTag (TIFFTAG_MAKE)) != nullptr) { + if ((tag = exifRoot->getTag (TIFFTAG_MAKE)) != NULL) { TIFFSetField (out, TIFFTAG_MAKE, tag->getValue()); } - if ((tag = exifRoot->getTag (TIFFTAG_DATETIME)) != nullptr) { + if ((tag = exifRoot->getTag (TIFFTAG_DATETIME)) != NULL) { TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue()); } - if ((tag = exifRoot->getTag (TIFFTAG_ARTIST)) != nullptr) { + if ((tag = exifRoot->getTag (TIFFTAG_ARTIST)) != NULL) { TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue()); } - if ((tag = exifRoot->getTag (TIFFTAG_COPYRIGHT)) != nullptr) { + if ((tag = exifRoot->getTag (TIFFTAG_COPYRIGHT)) != NULL) { TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue()); } @@ -1442,7 +1420,7 @@ void png_flush(png_structp png_ptr) FILE *io_ptr; io_ptr = (FILE *)(png_get_io_ptr(png_ptr)); - if (io_ptr != nullptr) { + if (io_ptr != NULL) { fflush(io_ptr); } } diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 681da1f3d..59d46035b 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -41,10 +41,10 @@ class ImageMatrices { public: - double rgb_cam[3][3]; - double cam_rgb[3][3]; - double xyz_cam[3][3]; - double cam_xyz[3][3]; + double rgb_cam[3][3] = {}; + double cam_rgb[3][3] = {}; + double xyz_cam[3][3] = {}; + double cam_xyz[3][3] = {}; }; class ImageSource : public InitialImage @@ -100,7 +100,7 @@ public: } virtual void getFullSize (int& w, int& h, int tr = TR_NONE) {} - virtual void getSize (int tran, PreviewProps pp, int& w, int& h) {} + virtual void getSize (PreviewProps pp, int& w, int& h) = 0; virtual int getRotateDegree() const { return 0; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 981a1ebd7..2b65e17e4 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -23,6 +23,7 @@ #include "../rtgui/ppversion.h" #include "colortemp.h" #include "improcfun.h" +#include "iccstore.h" #ifdef _OPENMP #include #endif @@ -32,16 +33,15 @@ namespace rtengine extern const Settings* settings; ImProcCoordinator::ImProcCoordinator () - : orig_prev(nullptr), oprevi(nullptr), oprevl(nullptr), nprevl(nullptr), previmg(nullptr), workimg(nullptr), - ncie(nullptr), imgsrc(nullptr), shmap(nullptr), lastAwbEqual(0.), ipf(¶ms, true), monitorIntent(RI_RELATIVE), scale(10), - highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), - bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(NAN), + : orig_prev(NULL), oprevi(NULL), oprevl(NULL), nprevl(NULL), previmg(NULL), workimg(NULL), + ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), monitorIntent(RI_RELATIVE), + softProof(false), gamutCheck(false), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), + allocated(false), bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(NAN), + ctColorCurve(), hltonecurve(65536), shtonecurve(65536), tonecurve(65536, 0), //,1); - chaut(0.f), redaut(0.f), blueaut(0.f), maxredaut(0.f), maxblueaut(0.f), minredaut(0.f), minblueaut(0.f), nresi(0.f), - chromina(0.f), sigma(0.f), lumema(0.f), lumacurve(32770, 0), // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation chroma_acurve(65536, 0), chroma_bcurve(65536, 0), @@ -84,12 +84,12 @@ ImProcCoordinator::ImProcCoordinator () rcurvehist(256), rcurvehistCropped(256), rbeforehist(256), gcurvehist(256), gcurvehistCropped(256), gbeforehist(256), bcurvehist(256), bcurvehistCropped(256), bbeforehist(256), + fw(0), fh(0), tr(0), fullw(1), fullh(1), pW(-1), pH(-1), - plistener(nullptr), imageListener(nullptr), aeListener(nullptr), acListener(nullptr), abwListener(nullptr), actListener(nullptr), adnListener(nullptr), awavListener(nullptr), dehaListener(nullptr), hListener(nullptr), - resultValid(false), changeSinceLast(0), updaterRunning(false), destroying(false), utili(false), autili(false), wavcontlutili(false), - butili(false), ccutili(false), cclutili(false), clcutili(false), opautili(false), conversionBuffer(1, 1) - + plistener(NULL), imageListener(NULL), aeListener(NULL), acListener(NULL), abwListener(NULL), actListener(NULL), adnListener(NULL), awavListener(NULL), dehaListener(NULL), hListener(NULL), + resultValid(false), lastOutputProfile("BADFOOD"), lastOutputIntent(RI__COUNT), lastOutputBPC(false), thread(nullptr), changeSinceLast(0), updaterRunning(false), destroying(false), utili(false), autili(false), wavcontlutili(false), + butili(false), ccutili(false), cclutili(false), clcutili(false), opautili(false), conversionBuffer(1, 1), colourToningSatLimit(0.f), colourToningSatLimitOpacity(0.f) {} void ImProcCoordinator::assign (ImageSource* imgsrc) @@ -138,9 +138,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) int readyphase = 0; bwAutoR = bwAutoG = bwAutoB = -9000.f; - chaut = redaut = blueaut = maxredaut = maxblueaut = nresi = highresi = 0.f; - chromina = sigma = lumema = 0.f; - minredaut = minblueaut = 10000.f; if (todo == CROP && ipf.needsPCVignetting()) { todo |= TRANSFORM; // Change about Crop does affect TRANSFORM @@ -443,11 +440,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, - vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale == 1 ? 1 : 1); + vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, 1); - CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, scale == 1 ? 1 : 1); - CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, scale == 1 ? 1 : 1); - CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, scale == 1 ? 1 : 1); + CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, 1); + CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, 1); + CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, 1); opautili = false; @@ -471,7 +468,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } if(params.blackwhite.enabled) { - CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, scale == 1 ? 1 : 1); + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, 1); } colourToningSatLimit = float(params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; @@ -539,7 +536,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) DCPProfile::ApplyState as; DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); - ipf.rgbProc (oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, + ipf.rgbProc (oprevi, oprevl, NULL, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, colourToningSatLimit , colourToningSatLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, dcpProf, as); if(params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { @@ -611,7 +608,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) // ipf.MSR(nprevl, nprevl->W, nprevl->H, 1); histCCurve.clear(); histLCurve.clear(); - ipf.chromiLuminanceCurve (nullptr, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve); + ipf.chromiLuminanceCurve (NULL, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve); ipf.vibrance(nprevl); if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { @@ -765,7 +762,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) delete ncie; } - ncie = nullptr; + ncie = NULL; if (CAMBrightCurveJ) { CAMBrightCurveJ.reset(); @@ -778,8 +775,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } // Update the monitor color transform if necessary - if (todo & M_MONITOR) { - ipf.updateColorProfiles(params.icm, monitorProfile, monitorIntent); + if ((todo & M_MONITOR) || (lastOutputProfile!=params.icm.output) || lastOutputIntent!=params.icm.outputIntent || lastOutputBPC!=params.icm.outputBPC) { + lastOutputProfile = params.icm.output; + lastOutputIntent = params.icm.outputIntent; + lastOutputBPC = params.icm.outputBPC; + ipf.updateColorProfiles(params.icm, monitorProfile, monitorIntent, softProof, gamutCheck); } // process crop, if needed @@ -794,20 +794,12 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) MyMutex::MyLock prevImgLock(previmg->getMutex()); try { + // Computing the preview image, i.e. converting from WCS->Monitor color space (soft-proofing disabled) or WCS->Output profile->Monitor color space (soft-proofing enabled) ipf.lab2monitorRgb (nprevl, previmg); + + // Computing the internal image for analysis, i.e. conversion from WCS->Output profile delete workimg; - Glib::ustring outProfile = params.icm.output; - - if(settings->HistogramWorking) { - Glib::ustring workProfile = params.icm.working; - workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, workProfile, RI_RELATIVE, true); // HOMBRE: was RELATIVE by default in lab2rgb, is it safe to assume we have to use it again ? - } else { - if (params.icm.output.empty() || params.icm.output == ColorManagementParams::NoICMString) { - outProfile = "sRGB"; - } - - workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, outProfile, params.icm.outputIntent, false); - } + workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, params.icm); } catch(char * str) { progress ("Error converting file...", 0); return; @@ -849,19 +841,19 @@ void ImProcCoordinator::freeAll () delete oprevi; } - oprevi = nullptr; + oprevi = NULL; delete orig_prev; - orig_prev = nullptr; + orig_prev = NULL; delete oprevl; - oprevl = nullptr; + oprevl = NULL; delete nprevl; - nprevl = nullptr; + nprevl = NULL; if (ncie) { delete ncie; } - ncie = nullptr; + ncie = NULL; if (imageListener) { imageListener->delImage (previmg); @@ -875,7 +867,7 @@ void ImProcCoordinator::freeAll () delete shmap; } - shmap = nullptr; + shmap = NULL; } @@ -905,7 +897,7 @@ void ImProcCoordinator::setScale (int prevscale) do { prevscale--; PreviewProps pp (0, 0, fw, fh, prevscale); - imgsrc->getSize (tr, pp, nW, nH); + imgsrc->getSize (pp, nW, nH); } while(nH < 400 && prevscale > 1 && (nW * nH < 1000000) ); // sctually hardcoded values, perhaps a better choice is possible if (settings->verbose) { @@ -1094,7 +1086,7 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int & MyMutex::MyLock lock(mProcessing); - LCPMapper *pLCPMap = nullptr; + LCPMapper *pLCPMap = NULL; if (params.lensProf.lcpFile.length() && imgsrc->getMetaData()->getFocalLen() > 0) { LCPProfile *pLCPProf = lcpStore->getProfile(params.lensProf.lcpFile); @@ -1134,6 +1126,18 @@ void ImProcCoordinator::getMonitorProfile (Glib::ustring& profile, RenderingInte intent = monitorIntent; } +void ImProcCoordinator::setSoftProofing (bool softProof, bool gamutCheck) +{ + this->softProof = softProof; + this->gamutCheck = gamutCheck; +} + +void ImProcCoordinator::getSoftProofing (bool &softProof, bool &gamutCheck) +{ + softProof = this->softProof; + gamutCheck = this->gamutCheck; +} + void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname, bool apply_wb) { @@ -1262,7 +1266,7 @@ void ImProcCoordinator::startProcessing () if (!destroying) { if (!updaterRunning) { updaterThreadStart.lock (); - thread = nullptr; + thread = NULL; updaterRunning = true; updaterThreadStart.unlock (); diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 0a0cbb2b0..2cc767b39 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -57,8 +57,8 @@ protected: Imagefloat *oprevi; LabImage *oprevl; LabImage *nprevl; - Image8 *previmg; - Image8 *workimg; + Image8 *previmg; // displayed image in monitor color space, showing the output profile as well (soft-proofing enabled, which then correspond to workimg) or not + Image8 *workimg; // internal image in output color space for analysis CieImage *ncie; ImageSource* imgsrc; @@ -73,8 +73,9 @@ protected: ImProcFunctions ipf; Glib::ustring monitorProfile; - RenderingIntent monitorIntent; + bool softProof; + bool gamutCheck; int scale; bool highDetailPreprocessComputed; @@ -90,7 +91,6 @@ protected: LUTf hltonecurve; LUTf shtonecurve; LUTf tonecurve; - float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema; LUTf lumacurve; LUTf chroma_acurve; @@ -179,6 +179,13 @@ protected: MyMutex mProcessing; ProcParams params; + // for optimization purpose, the output profile, output rendering intent and + // output BPC will trigger a regeneration of the profile on parameter change only + // and automatically + Glib::ustring lastOutputProfile; + RenderingIntent lastOutputIntent; + bool lastOutputBPC; + // members of the updater: Glib::Thread* thread; MyMutex updaterThreadStart; @@ -256,6 +263,8 @@ public: void setMonitorProfile (const Glib::ustring& profile, RenderingIntent intent); void getMonitorProfile (Glib::ustring& profile, RenderingIntent& intent) const; + void setSoftProofing (bool softProof, bool gamutCheck); + void getSoftProofing (bool &softProof, bool &gamutCheck); bool updateTryLock () { @@ -327,7 +336,7 @@ public: } struct DenoiseInfoStore { - DenoiseInfoStore () : valid(false) {} + DenoiseInfoStore () : chM(0), max_r{}, max_b{}, ch_M{}, valid(false) {} float chM; float max_r[9]; float max_b[9]; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 423a6b341..8e8a333a6 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -61,14 +61,6 @@ ImProcFunctions::~ImProcFunctions () if (monitorTransform) { cmsDeleteTransform (monitorTransform); } - - if (output2monitorTransform) { - cmsDeleteTransform (output2monitorTransform); - } - - if (lab2outputTransform) { - cmsDeleteTransform (lab2outputTransform); - } } void ImProcFunctions::setScale (double iscale) @@ -76,24 +68,14 @@ void ImProcFunctions::setScale (double iscale) scale = iscale; } -void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent) +void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck) { // set up monitor transform if (monitorTransform) { cmsDeleteTransform (monitorTransform); } - if (output2monitorTransform) { - cmsDeleteTransform (output2monitorTransform); - } - - if (lab2outputTransform) { - cmsDeleteTransform (lab2outputTransform); - } - monitorTransform = nullptr; - output2monitorTransform = nullptr; - lab2outputTransform = nullptr; #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB @@ -101,20 +83,57 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con if (monitor) { MyMutex::MyLock lcmsLock (*lcmsMutex); + + cmsUInt32Number flags; cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); - monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, monitorIntent, - cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is for thread safety, NOOPTIMIZE for precision - Glib::ustring outputProfile; + bool softProofCreated = false; - if (!icm.output.empty() && icm.output != ColorManagementParams::NoICMString) { - outputProfile = icm.output; - cmsHPROFILE jprof = iccStore->getProfile(outputProfile); - - if (jprof) { - lab2outputTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, jprof, TYPE_RGB_FLT, icm.outputIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); - output2monitorTransform = cmsCreateTransform (jprof, TYPE_RGB_FLT, monitor, TYPE_RGB_8, monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); + if (softProof) { + cmsHPROFILE oprof = nullptr; + if(icm.gamma != "default" || icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 + GammaValues ga; + iccStore->getGammaArray(icm, ga); + oprof = iccStore->createGammaProfile (icm, ga); } + else if (!icm.output.empty() && icm.output != ColorManagementParams::NoICMString) { + if(icm.gamma != "default" || icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 + GammaValues ga; + iccStore->getGammaArray(icm, ga); + oprof = iccStore->createCustomGammaOutputProfile (icm, ga); + } else { + oprof = iccStore->getProfile(icm.output); + } + } + + if (oprof) { + // NOCACHE is for thread safety, NOOPTIMIZE for precision + flags = cmsFLAGS_SOFTPROOFING | cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + if (gamutCheck) { + flags |= cmsFLAGS_GAMUTCHECK; + } + monitorTransform = cmsCreateProofingTransform( + iprof, TYPE_Lab_FLT, + monitor, TYPE_RGB_8, + oprof, + monitorIntent, icm.outputIntent, + flags + ); + if (monitorTransform) { + softProofCreated = true; + } + } + } + + if (!softProofCreated) { + flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (settings->monitorBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, monitorIntent, flags); } cmsCloseProfile(iprof); @@ -524,7 +543,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh xw2 = xwd; yw2 = ywd; zw2 = zwd; - } else if(params->colorappearance.wbmodel == "RawTCAT02") { + } else /*if(params->colorappearance.wbmodel == "RawTCAT02")*/ { xw1 = xw; // Settings RT WB are used for CAT02 => mix , CAT02 is use for output device (screen: D50 D65, projector: lamp, LED) see preferences yw1 = yw; zw1 = zw; @@ -1034,7 +1053,6 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh // if(!params->epd.enabled || !params->colorappearance.tonecie || !settings->autocielab){ // if(!params->epd.enabled || !params->colorappearance.tonecie || !params->colorappearance.sharpcie){ - int posl, posc; double brli = 327.; double chsacol = 327.; int libr = 0; @@ -1065,9 +1083,10 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh jp = true; if(pW != 1) { //only with improccoordinator + int posl; if(libr == 1) { posl = CLIP((int)(Q * brli)); //40.0 to 100.0 approximative factor for Q - 327 for J - } else if(libr == 0) { + } else /*if(libr == 0)*/ { posl = CLIP((int)(J * brli)); //327 for J } @@ -1077,11 +1096,12 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh chropC = true; if(pW != 1) { //only with improccoordinator + int posc; if(colch == 0) { posc = CLIP((int)(C * chsacol)); //450.0 approximative factor for s 320 for M } else if(colch == 1) { posc = CLIP((int)(s * chsacol)); - } else if(colch == 2) { + } else /*if(colch == 2)*/ { posc = CLIP((int)(M * chsacol)); } @@ -1303,7 +1323,6 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh ncie->C_p[i][j] = (ncie->M_p[i][j]) / co_e; //show histogram in CIECAM mode (Q,J, M,s,C) - int posl, posc; double brli = 327.; double chsacol = 327.; int libr = 0; @@ -1335,9 +1354,10 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh jp = true; if(pW != 1) { //only with improccoordinator + int posl; if(libr == 1) { posl = CLIP((int)(ncie->Q_p[i][j] * brli)); //40.0 to 100.0 approximative factor for Q - 327 for J - } else if(libr == 0) { + } else /*if(libr == 0)*/ { posl = CLIP((int)(ncie->J_p[i][j] * brli)); //327 for J } @@ -1347,12 +1367,13 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh chropC = true; if(pW != 1) { //only with improccoordinator + int posc; if(colch == 0) { posc = CLIP((int)(ncie->C_p[i][j] * chsacol)); //450.0 approximative factor for s 320 for M } else if(colch == 1) { sa_t = 100.f * sqrt(ncie->C_p[i][j] / ncie->Q_p[i][j]); //Q_p always > 0 posc = CLIP((int)(sa_t * chsacol)); - } else if(colch == 2) { + } else /*if(colch == 2)*/ { posc = CLIP((int)(ncie->M_p[i][j] * chsacol)); } @@ -1822,7 +1843,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int xw2 = xwd; yw2 = ywd; zw2 = zwd; - } else if(params->colorappearance.wbmodel == "RawTCAT02") { + } else /*if(params->colorappearance.wbmodel == "RawTCAT02")*/ { xw1 = xw; // Settings RT WB are used for CAT02 => mix , CAT02 is use for output device (screen: D50 D65, projector: lamp, LED) see preferences yw1 = yw; zw1 = zw; @@ -2680,8 +2701,6 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int for (int i = 0; i < height; i++) { // update CIECAM with new values after tone-mapping for (int j = 0; j < width; j++) { - float xx, yy, zz; - float x, y, z; // if(epdEnabled) ncie->J_p[i][j]=(100.0f* ncie->Q_p[i][j]*ncie->Q_p[i][j])/(w_h*w_h); if(epdEnabled) { @@ -4663,7 +4682,6 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float h, s, l; float r = tmpImage->r(i, j); float g = tmpImage->g(i, j); float b = tmpImage->b(i, j); @@ -6160,8 +6178,8 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (settings->verbose) { t2e.set(); printf("Color::AllMunsellLch (correction performed in %d usec):\n", t2e.etime(t1e)); - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); - printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%i\n", MunsDebugInfo->maxdhuelum[0], MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%u\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%u\n", MunsDebugInfo->maxdhuelum[0], MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); } delete MunsDebugInfo; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 9eedfde2a..7ea7bbecf 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -194,27 +194,9 @@ public: }; double lumimul[3]; -// float chau; -// float chred; -// float chblue; -// float maxchred; -// float maxchblue; -// float minchred; -// float minchblue; -// float resid;//used by noise_residual -// float residred;//used by noise_residual -// float residblue;//used by noise_residual -// int nb; - int nbresid; - float redresid; - float blueresid; -// float maxredresid;//used by noise_residual -// float maxblueresid;//used by noise_residual -// int comptlevel; - ImProcFunctions (const ProcParams* iparams, bool imultiThread = true) - : monitorTransform(nullptr), lab2outputTransform(nullptr), output2monitorTransform(nullptr), params(iparams), scale(1), multiThread(imultiThread) {} + : monitorTransform(NULL), lab2outputTransform(NULL), output2monitorTransform(NULL), params(iparams), scale(1), multiThread(imultiThread), lumimul{} {} ~ImProcFunctions (); void setScale (double iscale); @@ -223,7 +205,7 @@ public: bool needsPCVignetting (); void firstAnalysis (const Imagefloat* const working, const ProcParams ¶ms, LUTu & vhist16); - void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent); + void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck); void rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn ); @@ -279,7 +261,7 @@ public: void EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params& cp, int W_L, int H_L, float max0, float min0); float *CompressDR(float *Source, int skip, struct cont_params &cp, int W_L, int H_L, float Compression, float DetailBoost, float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Compressed); void ContrastResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params &cp, int W_L, int H_L, float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx); - float *ContrastDR(float *Source, int skip, struct cont_params &cp, int W_L, int H_L, float Compression, float DetailBoost, float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Contrast = nullptr); + float *ContrastDR(float *Source, int skip, struct cont_params &cp, int W_L, int H_L, float Compression, float DetailBoost, float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Contrast = NULL); void EPDToneMap(LabImage *lab, unsigned int Iterates = 0, int skip = 1); void EPDToneMapCIE(CieImage *ncie, float a_w, float c_, float w_h, int Wid, int Hei, int begh, int endh, float minQ, float maxQ, unsigned int Iterates = 0, int skip = 1); @@ -314,11 +296,11 @@ public: void Aver(float * HH_Coeffs, int datalen, float &averagePlus, float &averageNeg, float &max, float &min); void Sigma(float * HH_Coeffs, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg); - void calckoe(float ** WavCoeffs_LL, const struct cont_params& cp, float ** koeLi, int level, int dir, int W_L, int H_L, float edd, float *maxkoeLi, float **tmC = nullptr); + void calckoe(float ** WavCoeffs_LL, const struct cont_params& cp, float ** koeLi, int level, int dir, int W_L, int H_L, float edd, float *maxkoeLi, float **tmC = NULL); - void Median_Denoise( float **src, float **dst, int width, int height, Median medianType, int iterations, int numThreads, float **buffer = nullptr); + void Median_Denoise( float **src, float **dst, int width, int height, Median medianType, int iterations, int numThreads, float **buffer = NULL); void RGB_denoise(int kall, Imagefloat * src, Imagefloat * dst, Imagefloat * calclum, float * ch_M, float *max_r, float *max_b, bool isRAW, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, const NoiseCurve & noiseLCurve , const NoiseCurve & noiseCCurve , float &chaut, float &redaut, float &blueaut, float &maxredaut, float & maxblueaut, float &nresi, float &highresi); void RGB_denoise_infoGamCurve(const procparams::DirPyrDenoiseParams & dnparams, const bool isRAW, LUTf &gamcurve, float &gam, float &gamthresh, float &gamslope); void RGB_denoise_info(Imagefloat * src, Imagefloat * provicalc, bool isRAW, LUTf &gamcurve, float gam, float gamthresh, float gamslope, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float & maxblueaut, float &minredaut, float & minblueaut, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, bool multiThread = false); @@ -335,7 +317,7 @@ public: const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb); void ShrinkAllL(wavelet_decomposition &WaveletCoeffs_L, float **buffer, int level, int dir, float *noisevarlum, float * madL, float * vari, int edge); void ShrinkAllAB(wavelet_decomposition &WaveletCoeffs_L, wavelet_decomposition &WaveletCoeffs_ab, float **buffer, int level, int dir, - float *noisevarchrom, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, float * madL, float * madaab = nullptr, bool madCalculated = false); + float *noisevarchrom, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, float * madL, float * madaab = NULL, bool madCalculated = false); void ShrinkAll_info(float ** WavCoeffs_a, float ** WavCoeffs_b, int level, int W_ab, int H_ab, int skip_ab, float **noisevarlum, float **noisevarchrom, float **noisevarhue, int width, int height, float noisevar_abr, float noisevar_abb, LabImage * noi, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut, bool autoch, int schoice, int lvl, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, float &maxchred, float &maxchblue, float &minchred, float &minchblue, int &nb, float &chau, float &chred, float &chblue, bool denoiseMethodRgb, bool multiThread); @@ -361,16 +343,15 @@ public: void Badpixelscam(CieImage * src, CieImage * dst, double radius, int thresh, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom, int hotbad); void BadpixelsLab(LabImage * src, LabImage * dst, double radius, int thresh, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom); - Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool standard_gamma); - Image16* lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw);// for gamma output - Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool bw);//without gamma ==>default + Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); + Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, GammaValues *ga=NULL); // CieImage *ciec; - bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LCPMapper *pLCPMap = nullptr); - bool transCoord (int W, int H, const std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef = -1, const LCPMapper *pLCPMap = nullptr); + bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LCPMapper *pLCPMap = NULL); + bool transCoord (int W, int H, const std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef = -1, const LCPMapper *pLCPMap = NULL); static void getAutoExp (const LUTu & histogram, int histcompr, double defgain, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh); static double getAutoDistor (const Glib::ustring& fname, int thumb_size); - double getTransformAutoFill (int oW, int oH, const LCPMapper *pLCPMap = nullptr); + double getTransformAutoFill (int oW, int oH, const LCPMapper *pLCPMap = NULL); void rgb2lab(const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace); void lab2rgb(const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace); }; diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 805fb766b..924f79e1f 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -32,6 +32,12 @@ namespace rtengine extern const Settings* settings; +// Used in ImProcCoordinator::updatePreviewImage (rtengine/improccoordinator.cc) +// Crop::update (rtengine/dcrop.cc) +// Thumbnail::processImage (rtengine/rtthumbnail.cc) +// +// If monitorTransform, divide by 327.68 then apply monitorTransform (which can integrate soft-proofing) +// otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) { if (monitorTransform) { @@ -61,21 +67,13 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) float* ra = lab->a[i]; float* rb = lab->b[i]; - float fy, fx, fz, x_, y_, z_, LL; - for (int j = 0; j < W; j++) { buffer[iy++] = rL[j] / 327.68f; buffer[iy++] = ra[j] / 327.68f; buffer[iy++] = rb[j] / 327.68f; } - if (!settings->HistogramWorking && output2monitorTransform && lab2outputTransform) { - AlignedBuffer buf(3 * W); - cmsDoTransform (lab2outputTransform, buffer, buf.data, W); - cmsDoTransform (output2monitorTransform, buf.data, data + ix, W); - } else { - cmsDoTransform (monitorTransform, buffer, data + ix, W); - } + cmsDoTransform (monitorTransform, buffer, data + ix, W); } } // End of parallelization } else { @@ -115,8 +113,18 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) } } -Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool standard_gamma) + + +// Used in ImProcCoordinator::updatePreviewImage (rtengine/improccoordinator.cc) +// Crop::update (rtengine/dcrop.cc) +// +// Generate an Image8 +// +// If output profile used, divide by 327.68 then apply the "profile" profile (eventually with a standard gamma) +// otherwise divide by 327.68, convert to xyz and apply the RGB transform, before converting with gamma2curve +Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm) { + //gamutmap(lab); if (cx < 0) { cx = 0; @@ -135,9 +143,22 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, } Image8* image = new Image8 (cw, ch); - + Glib::ustring profile; cmsHPROFILE oprof = iccStore->getProfile (profile); + bool standard_gamma; + + if(settings->HistogramWorking) { + profile = icm.working; + standard_gamma = true; + } else { + profile = icm.output; + if (icm.output.empty() || icm.output == ColorManagementParams::NoICMString) { + profile = "sRGB"; + } + standard_gamma = false; + } + if (oprof) { cmsHPROFILE oprofG = oprof; @@ -145,11 +166,16 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, oprofG = ICCStore::makeStdGammaProfile(oprof); } + cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + printf("lab2rgb / bpc=true\n"); + } + else printf("lab2rgb / bpc=false\n"); lcmsMutex->lock (); - cmsHPROFILE hLab = cmsCreateLab4Profile(nullptr); - cmsHTRANSFORM hTransform = cmsCreateTransform (hLab, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, intent, - cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is important for thread safety - cmsCloseProfile(hLab); + cmsHPROFILE LabIProf = cmsCreateLab4Profile(NULL); + cmsHTRANSFORM hTransform = cmsCreateTransform (LabIProf, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, icm.outputIntent, flags); // NOCACHE is important for thread safety + cmsCloseProfile(LabIProf); lcmsMutex->unlock (); unsigned char *data = image->data; @@ -220,8 +246,24 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, return image; } -// for default (not gamma) -Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool bw) + + +/** @brief Convert the final Lab image to the output RGB color space + * + * Used in processImage (rtengine/simpleprocess.cc) + * + * Provide a pointer to a 7 floats array for "ga" (uninitialized ; this array will be filled with the gamma values) if you want + * to use the custom gamma scenario. Thoses gamma values will correspond to the ones of the chosen standard output profile + * (Prophoto if non standard output profile given) + * + * If "ga" is NULL, then we're considering standard gamma with the chosen output profile. + * + * Generate an Image16 + * + * If a custom gamma profile can be created, divide by 327.68, convert to xyz and apply the custom gamma transform + * otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve + */ +Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, GammaValues *ga) { if (cx < 0) { @@ -241,49 +283,37 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int } Image16* image = new Image16 (cw, ch); - cmsHPROFILE oprof = iccStore->getProfile (profile); + + cmsHPROFILE oprof = NULL; + if (ga) { + lcmsMutex->lock (); + iccStore->getGammaArray(icm, *ga); + oprof = iccStore->createGammaProfile(icm, *ga); + lcmsMutex->unlock (); + printf("iccStore->createGammaProfile(icm, *ga);\n"); + } else { + oprof = iccStore->getProfile (icm.output); + printf("iccStore->getProfile (%s);\n", icm.output.c_str()); + } if (oprof) { -#ifdef _OPENMP - #pragma omp parallel for if (multiThread) -#endif - - for (int i = cy; i < cy + ch; i++) { - float* rL = lab->L[i]; - float* ra = lab->a[i]; - float* rb = lab->b[i]; - short* xa = (short*)image->r(i - cy); - short* ya = (short*)image->g(i - cy); - short* za = (short*)image->b(i - cy); - - for (int j = cx; j < cx + cw; j++) { - float x_, y_, z_; - Color::Lab2XYZ(rL[j], ra[j], rb[j], x_, y_, z_); - - xa[j - cx] = float2uint16range(x_); - ya[j - cx] = float2uint16range(y_); - za[j - cx] = float2uint16range(z_); - - if(bw && y_ < 65535.f ) { //force Bw value and take highlight into account - xa[j - cx] = float2uint16range(y_ * Color::D50x); - za[j - cx] = float2uint16range(y_ * Color::D50z); - } - } + cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + printf("lab2rgb16 / icm.outputBPC=true / outputIntent=%d\n", icm.outputIntent); } - - cmsHPROFILE iprof = iccStore->getXYZProfile (); + else printf("lab2rgb16 / icm.outputBPC=false / outputIntent=%d\n", icm.outputIntent); lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_16, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); + cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_16, icm.outputIntent, flags); lcmsMutex->unlock (); - image->ExecCMSTransform(hTransform); - + image->ExecCMSTransform(hTransform, *lab, cx, cy); cmsDeleteTransform(hTransform); } else { #ifdef _OPENMP - #pragma omp parallel for if (multiThread) + #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif - for (int i = cy; i < cy + ch; i++) { float R, G, B; float* rL = lab->L[i]; @@ -297,279 +327,10 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int float fz = fy - (0.005f * rb[j]) / 327.68f; float LL = rL[j] / 327.68f; - float x_ = 65535.0f * (float) Color::f2xyz(fx) * Color::D50x; + float x_ = 65535.0f * Color::f2xyz(fx) * Color::D50x; //float y_ = 65535.0 * Color::f2xyz(fy); - float z_ = 65535.0f * (float) Color::f2xyz(fz) * Color::D50z; - float y_ = (LL > Color::epskap) ? (float) 65535.0f * fy * fy * fy : 65535.0f * LL / Color::kappa; - - Color::xyz2srgb(x_, y_, z_, R, G, B); - - image->r(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(R)]; - image->g(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(G)]; - image->b(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(B)]; - } - } - } - - return image; -} - - -// for gamma options (BT709...sRGB linear...) -Image16* ImProcFunctions::lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw) -{ - - if (cx < 0) { - cx = 0; - } - - if (cy < 0) { - cy = 0; - } - - if (cx + cw > lab->W) { - cw = lab->W - cx; - } - - if (cy + ch > lab->H) { - ch = lab->H - cy; - } - - Image16* image = new Image16 (cw, ch); - float p1, p2, p3, p4, p5, p6; //primaries - - double pwr; - double ts; - ga6 = 0.0; - pwr = 1.0 / gampos; - ts = slpos; - - int t50; - int select_temp = 1; //5003K - const double eps = 0.000000001; // not divide by zero - - //primaries for 7 working profiles ==> output profiles - // eventually to adapt primaries if RT used special profiles ! - if (profi == "WideGamut") { - p1 = 0.7350; //Widegamut primaries - p2 = 0.2650; - p3 = 0.1150; - p4 = 0.8260; - p5 = 0.1570; - p6 = 0.0180; - select_temp = 1; - } else if (profi == "Adobe RGB") { - p1 = 0.6400; //Adobe primaries - p2 = 0.3300; - p3 = 0.2100; - p4 = 0.7100; - p5 = 0.1500; - p6 = 0.0600; - select_temp = 2; - } else if (profi == "sRGB") { - p1 = 0.6400; // sRGB primaries - p2 = 0.3300; - p3 = 0.3000; - p4 = 0.6000; - p5 = 0.1500; - p6 = 0.0600; - select_temp = 2; - } else if (profi == "BruceRGB") { - p1 = 0.6400; // Bruce primaries - p2 = 0.3300; - p3 = 0.2800; - p4 = 0.6500; - p5 = 0.1500; - p6 = 0.0600; - select_temp = 2; - } else if (profi == "Beta RGB") { - p1 = 0.6888; // Beta primaries - p2 = 0.3112; - p3 = 0.1986; - p4 = 0.7551; - p5 = 0.1265; - p6 = 0.0352; - select_temp = 1; - } else if (profi == "BestRGB") { - p1 = 0.7347; // Best primaries - p2 = 0.2653; - p3 = 0.2150; - p4 = 0.7750; - p5 = 0.1300; - p6 = 0.0350; - select_temp = 1; - } else if (profi == "Rec2020") { - p1 = 0.7080; // Rec2020 primaries - p2 = 0.2920; - p3 = 0.1700; - p4 = 0.7970; - p5 = 0.1310; - p6 = 0.0460; - select_temp = 2; - } else { - p1 = 0.7347; //ProPhoto and default primaries - p2 = 0.2653; - p3 = 0.1596; - p4 = 0.8404; - p5 = 0.0366; - p6 = 0.0001; - select_temp = 1; - } - - if (!freegamma) {//if Free gamma not selected - // gamma : ga0,ga1,ga2,ga3,ga4,ga5 by calcul - if(gam == "BT709_g2.2_s4.5") { - ga0 = 2.22; //BT709 2.2 4.5 - my prefered as D.Coffin - ga1 = 0.909995; - ga2 = 0.090005; - ga3 = 0.222222; - ga4 = 0.081071; - ga5 = 0.0; - } else if (gam == "sRGB_g2.4_s12.92") { - ga0 = 2.40; //sRGB 2.4 12.92 - RT default as Lightroom - ga1 = 0.947858; - ga2 = 0.052142; - ga3 = 0.077399; - ga4 = 0.039293; - ga5 = 0.0; - } else if (gam == "High_g1.3_s3.35") { - ga0 = 1.3 ; //for high dynamic images - ga1 = 0.998279; - ga2 = 0.001721; - ga3 = 0.298507; - ga4 = 0.005746; - ga5 = 0.0; - } else if (gam == "Low_g2.6_s6.9") { - ga0 = 2.6 ; //gamma 2.6 variable : for low contrast images - ga1 = 0.891161; - ga2 = 0.108839; - ga3 = 0.144928; - ga4 = 0.076332; - ga5 = 0.0; - } else if (gam == "linear_g1.0") { - ga0 = 1.0; //gamma=1 linear : for high dynamic images (cf : D.Coffin...) - ga1 = 1.; - ga2 = 0.; - ga3 = 1. / eps; - ga4 = 0.; - ga5 = 0.0; - } else if (gam == "standard_g2.2") { - ga0 = 2.2; //gamma=2.2 (as gamma of Adobe, Widegamut...) - ga1 = 1.; - ga2 = 0.; - ga3 = 1. / eps; - ga4 = 0.; - ga5 = 0.0; - } else if (gam == "standard_g1.8") { - ga0 = 1.8; //gamma=1.8 (as gamma of Prophoto) - ga1 = 1.; - ga2 = 0.; - ga3 = 1. / eps; - ga4 = 0.; - ga5 = 0.0; - } - } else { //free gamma selected - if(slpos == 0) { - slpos = eps; - } - - double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5; //gamma parameters - int mode = 0, imax = 0; - - Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 - ga4 = g_a3 * ts; - ga0 = gampos; - ga1 = 1. / (1.0 + g_a4); - ga2 = g_a4 / (1.0 + g_a4); - ga3 = 1. / slpos; - ga5 = 0.0; - - } - - if(select_temp == 1) { - t50 = 5003; // for Widegamut, Prophoto Best, Beta D50 - } else if (select_temp == 2) { - t50 = 6504; // for sRGB, AdobeRGB, Bruce Rec2020 D65 - } - - cmsCIExyY xyD; - cmsCIExyYTRIPLE Primaries = {{p1, p2, 1.0},//red primaries - {p3, p4, 1.0}, // green - {p5, p6, 1.0} //blue - }; - cmsToneCurve* GammaTRC[3]; - cmsFloat64Number Parameters[7]; - Parameters[0] = ga0; - Parameters[1] = ga1; - Parameters[2] = ga2; - Parameters[3] = ga3; - Parameters[4] = ga4; - Parameters[5] = ga5; - Parameters[6] = ga6; -// 7 parameters for smoother curves - cmsWhitePointFromTemp(&xyD, t50); - GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(nullptr, 5, Parameters);//5 = more smoother than 4 - cmsHPROFILE oprofdef = cmsCreateRGBProfileTHR(nullptr, &xyD, &Primaries, GammaTRC); //oprofdef becomes Outputprofile - - cmsFreeToneCurve(GammaTRC[0]); - - if (oprofdef) { -#ifdef _OPENMP - #pragma omp parallel for if (multiThread) -#endif - - for (int i = cy; i < cy + ch; i++) { - float* rL = lab->L[i]; - float* ra = lab->a[i]; - float* rb = lab->b[i]; - short* xa = (short*)image->r(i - cy); - short* ya = (short*)image->g(i - cy); - short* za = (short*)image->b(i - cy); - - for (int j = cx; j < cx + cw; j++) { - float x_, y_, z_; - Color::Lab2XYZ(rL[j], ra[j], rb[j], x_, y_, z_); - - xa[j - cx] = float2uint16range(x_); - ya[j - cx] = float2uint16range(y_); - za[j - cx] = float2uint16range(z_); - - if(bw && y_ < 65535.f) { //force Bw value and take highlight into account - xa[j - cx] = float2uint16range(y_ * Color::D50x); - za[j - cx] = float2uint16range(y_ * Color::D50z); - } - } - } - - cmsHPROFILE iprof = iccStore->getXYZProfile (); - lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprofdef, TYPE_RGB_16, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); - lcmsMutex->unlock (); - - image->ExecCMSTransform(hTransform); - cmsDeleteTransform(hTransform); - } else { -#ifdef _OPENMP - #pragma omp parallel for if (multiThread) -#endif - - for (int i = cy; i < cy + ch; i++) { - float R, G, B; - float* rL = lab->L[i]; - float* ra = lab->a[i]; - float* rb = lab->b[i]; - - for (int j = cx; j < cx + cw; j++) { - - float fy = (0.0086206897f * rL[j]) / 327.68f + 0.1379310345f; // (L+16)/116 - float fx = (0.002f * ra[j]) / 327.68f + fy; - float fz = fy - (0.005f * rb[j]) / 327.68f; - float LL = rL[j] / 327.68f; - - float x_ = 65535.0f * (float) Color::f2xyz(fx) * Color::D50x; - //float y_ = 65535.0 * Color::f2xyz(fy); - float z_ = 65535.0f * (float) Color::f2xyz(fz) * Color::D50z; - float y_ = (LL > Color::epskap) ? (float) 65535.0 * fy * fy * fy : 65535.0f * LL / Color::kappa; + float z_ = 65535.0f * Color::f2xyz(fz) * Color::D50z; + float y_ = (LL > (float)Color::epskap) ? 65535.0f * fy * fy * fy : 65535.0f * LL / (float)Color::kappa; Color::xyz2srgb(x_, y_, z_, R, G, B); diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 06f779875..2dbdbafb1 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -140,8 +140,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e { if (deh.enabled) {//enabled - float mean, stddv, maxtr, mintr; - float delta; + float maxtr, mintr; constexpr float eps = 2.f; bool useHsl = deh.retinexcolorspace == "HSLLOG"; bool useHslLin = deh.retinexcolorspace == "HSLLIN"; @@ -551,8 +550,8 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e delete [] buffer; delete [] srcBuffer; - mean = 0.f; - stddv = 0.f; + float mean = 0.f; + float stddv = 0.f; // I call mean_stddv2 instead of mean_stddv ==> logBetaGain mean_stddv2( luminance, mean, stddv, W_L, H_L, maxtr, mintr); @@ -658,7 +657,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e maxi = maxtr - epsil; } - delta = maxi - mini; + float delta = maxi - mini; //printf("maxi=%f mini=%f mean=%f std=%f delta=%f maxtr=%f mintr=%f\n", maxi, mini, mean, stddv, delta, maxtr, mintr); if ( !delta ) { @@ -691,7 +690,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e // I call mean_stddv2 instead of mean_stddv ==> logBetaGain mean_stddv2( luminance, mean, stddv, W_L, H_L, maxtr, mintr); - float asig, bsig, amax, bmax, amin, bmin; + float asig = 0.f, bsig = 0.f, amax = 0.f, bmax = 0.f, amin = 0.f, bmin = 0.f; if (dehagaintransmissionCurve && mean != 0.f && stddv != 0.f) { //if curve asig = 0.166666f / stddv; diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index 215763f43..60994175b 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -744,7 +744,7 @@ void ImProcFunctions::vibrance (LabImage* lab) printf(" Gamut: G1negat=%iiter G165535=%iiter G2negsat=%iiter G265535=%iiter\n", negat, moreRGB, negsat, moresat); if (MunsDebugInfo) { - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%u\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); } } diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 1ca5b78ec..ee8f10ad1 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -39,6 +39,7 @@ #include "opthelper.h" #include "median.h" #include "EdgePreservingDecomposition.h" +#include "iccstore.h" #ifdef _OPENMP #include diff --git a/rtengine/myfile.cc b/rtengine/myfile.cc index f9d0c3621..11a5b495b 100644 --- a/rtengine/myfile.cc +++ b/rtengine/myfile.cc @@ -361,7 +361,7 @@ int fscanf (IMFILE* f, const char* s ...) // of file data and vsscanf() won't tell us how many characters that // were parsed. However, only dcraw.cc code use it and only for "%f" and // "%d", so we make a dummy fscanf here just to support dcraw case. - char buf[50], *endptr; + char buf[50], *endptr = nullptr; int copy_sz = f->size - f->pos; if (copy_sz > sizeof(buf)) { @@ -377,6 +377,7 @@ int fscanf (IMFILE* f, const char* s ...) int i = strtol(buf, &endptr, 10); if (endptr == buf) { + va_end (ap); return 0; } @@ -386,6 +387,7 @@ int fscanf (IMFILE* f, const char* s ...) float f = strtof(buf, &endptr); if (endptr == buf) { + va_end (ap); return 0; } diff --git a/rtengine/processingjob.h b/rtengine/processingjob.h index c4f3eba38..2de426a31 100644 --- a/rtengine/processingjob.h +++ b/rtengine/processingjob.h @@ -37,7 +37,7 @@ public: : fname(fn), isRaw(iR), initialImage(nullptr), pparams(pp) {} ProcessingJobImpl (InitialImage* iImage, const procparams::ProcParams& pp) - : fname(""), initialImage(iImage), pparams(pp) + : fname(""), isRaw(true), initialImage(iImage), pparams(pp) { iImage->increaseRef(); } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 62d2a4ac1..52517e527 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -469,6 +469,7 @@ enum ProcEvent { EvcbdlMethod = 439, EvRetinexgaintransmission = 440, EvLskal = 441, + EvOBPCompens = 442, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index b0a7873e9..5a8ee39a6 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -927,6 +927,7 @@ void ColorManagementParams::setDefaults() working = "ProPhoto"; output = "RT_sRGB"; outputIntent = RI_RELATIVE; + outputBPC = true; gamma = "default"; gampos = 2.22; slpos = 4.5; @@ -2662,6 +2663,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_string ("Color Management", "OutputProfileIntent", intent); } + if (!pedited || pedited->icm.outputBPC) { + keyFile.set_boolean ("Color Management", "OutputBPC", icm.outputBPC); + } + if (!pedited || pedited->icm.gamma) { keyFile.set_string ("Color Management", "Gammafree", icm.gamma); } @@ -5921,6 +5926,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Color Management", "OutputBPC")) { + icm.outputBPC = keyFile.get_boolean ("Color Management", "OutputBPC"); + + if (pedited) { + pedited->icm.outputBPC = true; + } + } + if (keyFile.has_key ("Color Management", "Gammafree")) { icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 3a1c4487b..c65e89e24 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -65,9 +65,7 @@ public: protected: bool initEq1; bool _isDouble; -#ifndef NDEBUG - unsigned int part[5]; -#endif + public: Threshold (T bottom, T top, bool startAtOne) { @@ -969,6 +967,7 @@ public: Glib::ustring working; Glib::ustring output; RenderingIntent outputIntent; + bool outputBPC; static const Glib::ustring NoICMString; Glib::ustring gamma; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index a36f2e222..cb1c2a9c9 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -20,11 +20,12 @@ namespace rtengine extern const Settings* settings; RawImage::RawImage( const Glib::ustring &name ) - : data(nullptr) + : data(NULL) , prefilters(0) , filename(name) - , profile_data(nullptr) - , allocation(nullptr) + , profile_data(NULL) + , allocation(NULL) + , rotate_deg(0) { memset(maximum_c4, 0, sizeof(maximum_c4)); RT_matrix_from_constant = 0; @@ -44,22 +45,22 @@ RawImage::~RawImage() if(allocation) { delete [] allocation; - allocation = nullptr; + allocation = NULL; } if(float_raw_image) { delete [] float_raw_image; - float_raw_image = nullptr; + float_raw_image = NULL; } if(data) { delete [] data; - data = nullptr; + data = NULL; } if(profile_data) { delete [] profile_data; - profile_data = nullptr; + profile_data = NULL; } } @@ -400,9 +401,9 @@ skip_block: int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistener, double progressRange) { ifname = filename.c_str(); - image = nullptr; + image = NULL; verbose = settings->verbose; - oprof = nullptr; + oprof = NULL; ifp = gfopen (ifname); // Maps to either file map or direct fopen @@ -414,18 +415,18 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene thumb_length = 0; thumb_offset = 0; - thumb_load_raw = nullptr; + thumb_load_raw = 0; use_camera_wb = 0; highlight = 1; half_size = 0; - raw_image = nullptr; + raw_image = 0; //***************** Read ALL raw file info identify (); if (!is_raw) { fclose(ifp); - ifp = nullptr; + ifp = NULL; if (plistener) { plistener->setProgress(1.0 * progressRange); @@ -531,7 +532,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene crop_masked_pixels(); free (raw_image); - raw_image = nullptr; + raw_image = NULL; } else { if (cc && cc->has_rawCrop()) { // foveon images int lm, tm, w, h; @@ -643,7 +644,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene if ( closeFile ) { fclose(ifp); - ifp = nullptr; + ifp = NULL; } if (plistener) { @@ -656,7 +657,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene float** RawImage::compress_image() { if( !image ) { - return nullptr; + return NULL; } if (isBayer() || isXtrans()) { @@ -699,7 +700,7 @@ float** RawImage::compress_image() } delete [] float_raw_image; - float_raw_image = nullptr; + float_raw_image = NULL; } else if (filters != 0 && !isXtrans()) { #pragma omp parallel for @@ -733,7 +734,7 @@ float** RawImage::compress_image() } free(image); // we don't need this anymore - image = nullptr; + image = NULL; return data; } @@ -782,7 +783,7 @@ void RawImage::getRgbCam (float rgbcam[3][4]) bool RawImage::get_thumbSwap() const { - return (order == 0x4949) == (ntohs(0x1234) == 0x1234); + return ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) ? true : false; } } //namespace rtengine diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 9e90764b2..12ac4330a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -423,25 +423,49 @@ extern const Settings* settings; RawImageSource::RawImageSource () : ImageSource() - , plistener(nullptr) + , W(0), H(0) + , plistener(NULL) , border(4) - , ri(nullptr) - , cache(nullptr) + , ri(NULL) + , cache(NULL) , rawData(0, 0) , green(0, 0) , red(0, 0) , blue(0, 0) + , lc00(0.0) + , lc01(0.0) + , lc02(0.0) + , lc10(0.0) + , lc11(0.0) + , lc12(0.0) + , lc20(0.0) + , lc21(0.0) + , lc22(0.0) + , hlmax{} + , clmax{} + , chmax{} + , scale_mul{} + , c_black{} + , c_white{} + , cblacksom{} + , ref_pre_mul{} + , refwb_red(0.0) + , refwb_green(0.0) + , refwb_blue(0.0) + , rgb_cam{} + , cam_rgb{} + , xyz_cam{} + , cam_xyz{} + , fuji(false) + , d1x(false) + , initialGain(0.0) + , camInitialGain(0.0) + , defGain(0.0) + , threshold(0) { - hrmap[0] = nullptr; - hrmap[1] = nullptr; - hrmap[2] = nullptr; - //needhr = NULL; - //hpmap = NULL; - camProfile = nullptr; - embProfile = nullptr; + camProfile = NULL; + embProfile = NULL; rgbSourceModified = false; - hlmax[0] = hlmax[1] = hlmax[2] = hlmax[3] = 0.f; - clmax[0] = clmax[1] = clmax[2] = clmax[3] = 0.f; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -462,13 +486,6 @@ RawImageSource::~RawImageSource () delete [] cache; } - if (hrmap[0] != nullptr) { - int dh = H / HR_SCALE; - freeJaggedArray(hrmap[0]); - freeJaggedArray(hrmap[1]); - freeJaggedArray(hrmap[2]); - } - if (camProfile) { cmsCloseProfile (camProfile); } @@ -872,12 +889,12 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as) { - DCPProfile *dcpProf = nullptr; + DCPProfile *dcpProf = NULL; cmsHPROFILE dummy; - findInputProfile(cmp.input, nullptr, (static_cast(getMetaData()))->getCamera(), &dcpProf, dummy); + findInputProfile(cmp.input, NULL, (static_cast(getMetaData()))->getCamera(), &dcpProf, dummy); - if (dcpProf == nullptr) { - return nullptr; + if (dcpProf == NULL) { + return NULL; } dcpProf->setStep2ApplyState(cmp.working, cmp.toneCurve, cmp.applyLookTable, cmp.applyBaselineExposureOffset, as); @@ -1453,10 +1470,9 @@ void RawImageSource::getFullSize (int& w, int& h, int tr) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) +void RawImageSource::getSize (PreviewProps pp, int& w, int& h) { - tran = defTransform (tran); w = pp.w / pp.skip + (pp.w % pp.skip > 0); h = pp.h / pp.skip + (pp.h % pp.skip > 0); } @@ -1629,7 +1645,7 @@ int RawImageSource::load (const Glib::ustring &fname, bool batch) plistener->setProgress (1.0); } - plistener = nullptr; // This must be reset, because only load() is called through progressConnector + plistener = NULL; // This must be reset, because only load() is called through progressConnector t2.set(); if( settings->verbose ) { @@ -1648,7 +1664,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le t1.set(); Glib::ustring newDF = raw.dark_frame; - RawImage *rid = nullptr; + RawImage *rid = NULL; if (!raw.df_autoselect) { if( !raw.dark_frame.empty()) { @@ -1686,7 +1702,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } //FLATFIELD start - RawImage *rif = nullptr; + RawImage *rif = NULL; if (!raw.ff_AutoSelect) { if( !raw.ff_file.empty()) { @@ -1697,7 +1713,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } - bool hasFlatField = (rif != nullptr); + bool hasFlatField = (rif != NULL); if( hasFlatField && settings->verbose) { printf( "Flat Field Correction:%s\n", rif->get_filename().c_str()); @@ -1723,7 +1739,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } // If darkframe selected, correct hotpixels found on darkframe - bp = nullptr; + bp = 0; if( raw.df_autoselect ) { bp = dfm.getHotPixels(idata->getMake(), idata->getModel(), idata->getISOSpeed(), idata->getShutterSpeed(), idata->getDateTimeAsTS()); @@ -1973,7 +1989,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } else if(retinexParams.gammaretinex == "hig") { retinexgamtab = &(Color::gammatab_145_3); } else if(retinexParams.gammaretinex == "fre") { - double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5; + GammaValues g_a; double pwr = 1.0 / retinexParams.gam; double gamm = retinexParams.gam; double ts = retinexParams.slope; @@ -1984,21 +2000,21 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } int mode = 0, imax = 0; - Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope + Color::calcGamma(pwr, ts, mode, imax, g_a); // call to calcGamma with selected gamma and slope // printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4); double start; double add; if(gamm2 < 1.) { - start = g_a2; - add = g_a4; + start = g_a[2]; + add = g_a[4]; } else { - start = g_a3; - add = g_a4; + start = g_a[3]; + add = g_a[4]; } - double mul = 1. + g_a4; + double mul = 1. + g_a[4]; lutTonereti(65536); @@ -2123,7 +2139,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar #endif for (; j < W - border; j++) { - float H, S, L; + float L; //rgb=>lab Color::rgb2hslfloat(red[i][j], green[i][j], blue[i][j], conversionBuffer[0][i - border][j - border], conversionBuffer[1][i - border][j - border], L); L *= 32768.f; @@ -2245,7 +2261,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC } else if(deh.gammaretinex == "hig") { retinexigamtab = &(Color::igammatab_145_3); } else if(deh.gammaretinex == "fre") { - double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5; + GammaValues g_a; double pwr = 1.0 / deh.gam; double gamm = deh.gam; double gamm2 = gamm; @@ -2256,18 +2272,18 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC std::swap(pwr, gamm); } - Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope + Color::calcGamma(pwr, ts, mode, imax, g_a); // call to calcGamma with selected gamma and slope - double mul = 1. + g_a4; + double mul = 1. + g_a[4]; double add; double start; if(gamm2 < 1.) { - start = g_a3; - add = g_a3; + start = g_a[3]; + add = g_a[3]; } else { - add = g_a4; - start = g_a2; + add = g_a[4]; + start = g_a[2]; } // printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4); @@ -2296,7 +2312,6 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC float **temp = conversionBuffer[2]; // one less dereference LUTf dLcurve; LUTu hist16RET; - float val; if(dehacontlutili && histLRETI) { hist16RET(32768); @@ -2305,7 +2320,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC dLcurve(32768); } - FlatCurve* chcurve = nullptr;//curve c=f(H) + FlatCurve* chcurve = NULL;//curve c=f(H) bool chutili = false; if (deh.enabled && deh.retinexMethod == "highli") { @@ -2314,7 +2329,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC if (!chcurve || chcurve->isIdentity()) { if (chcurve) { delete chcurve; - chcurve = nullptr; + chcurve = NULL; } } else { chutili = true; @@ -2369,7 +2384,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC // hist16RET.compressTo(histLRETI); // also remove declaration and init of dLcurve some lines above then and finally remove this comment :) for (int i = 0; i < 32768; i++) { - val = (double)i / 32767.0; + float val = (double)i / 32767.0; dLcurve[i] = val; } @@ -2393,14 +2408,8 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC for (; j < W - border; j++) { - float valp; - // if(chutili) { // c=f(H) - { - valp = float((chcurve->getVal(conversionBuffer[3][i - border][j - border]) - 0.5f)); - - conversionBuffer[1][i - border][j - border] *= (1.f + 2.f * valp); - } - // } + float valp = (chcurve->getVal(conversionBuffer[3][i - border][j - border]) - 0.5f); + conversionBuffer[1][i - border][j - border] *= (1.f + 2.f * valp); } } @@ -2629,7 +2638,7 @@ void RawImageSource::flushRawData() { if(cache) { delete [] cache; - cache = nullptr; + cache = 0; } if (rawData) { @@ -2822,7 +2831,7 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile if(raw.ff_AutoClipControl) { // determine maximum calculated value to avoid clipping - int clipControlGui = 0; +// int clipControlGui = 0; float maxval = 0.f; // xtrans files have only one black level actually, so we can simplify the code a bit #ifdef _OPENMP @@ -2857,7 +2866,7 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile // there's only one white level for xtrans if(maxval + black[0] > ri->get_white(0)) { limitFactor = ri->get_white(0) / (maxval + black[0]); - clipControlGui = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui +// clipControlGui = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui } } else { limitFactor = max((float)(100 - raw.ff_clipControl) / 100.f, 0.01f); @@ -3696,9 +3705,9 @@ void RawImageSource::getProfilePreprocParams(cmsHPROFILE in, float& gammaFac, fl copyright[0] = 0; if (cmsGetProfileInfoASCII(in, cmsInfoCopyright, cmsNoLanguage, cmsNoCountry, copyright, 256) > 0) { - if (strstr(copyright, "Phase One") != nullptr) { + if (strstr(copyright, "Phase One") != NULL) { gammaFac = 0.55556; // 1.8 - } else if (strstr(copyright, "Nikon Corporation") != nullptr) { + } else if (strstr(copyright, "Nikon Corporation") != NULL) { gammaFac = 0.5; lineFac = -0.4; lineSum = 1.35; // determined in reverse by measuring NX an RT developed colorchecker PNGs @@ -3767,7 +3776,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam return; } - if (dcpProf != nullptr) { + if (dcpProf != NULL) { // DCP processing const DCPProfile::Triple pre_mul_row = { pre_mul[0], @@ -3784,7 +3793,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam return; } - if (in == nullptr) { + if (in == NULL) { // use default camprofile, supplied by dcraw // in this case we avoid using the slllllooooooowwww lcms @@ -3860,10 +3869,10 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam camera_icc_type = CAMERA_ICC_TYPE_GENERIC; // Note: order the identification with the most detailed matching first since the more general ones may also match the more detailed - if ((strstr(copyright, "Leaf") != nullptr || - strstr(copyright, "Phase One A/S") != nullptr || - strstr(copyright, "Kodak") != nullptr || - strstr(copyright, "Creo") != nullptr) && + if ((strstr(copyright, "Leaf") != NULL || + strstr(copyright, "Phase One A/S") != NULL || + strstr(copyright, "Kodak") != NULL || + strstr(copyright, "Creo") != NULL) && (strstr(description, "LF2 ") == description || strstr(description, "LF3 ") == description || strstr(description, "LeafLF2") == description || @@ -3872,9 +3881,9 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam strstr(description, "MamiyaLF2") == description || strstr(description, "MamiyaLF3") == description)) { camera_icc_type = CAMERA_ICC_TYPE_LEAF; - } else if (strstr(copyright, "Phase One A/S") != nullptr) { + } else if (strstr(copyright, "Phase One A/S") != NULL) { camera_icc_type = CAMERA_ICC_TYPE_PHASE_ONE; - } else if (strstr(copyright, "Nikon Corporation") != nullptr) { + } else if (strstr(copyright, "Nikon Corporation") != NULL) { camera_icc_type = CAMERA_ICC_TYPE_NIKON; } } @@ -3893,7 +3902,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam transform_via_pcs_lab = true; separate_pcs_lab_highlights = true; // We transform to Lab because we can and that we avoid getting an unnecessary unmatched gamma conversion which we would need to revert. - hTransform = cmsCreateTransform (in, TYPE_RGB_FLT, nullptr, TYPE_Lab_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); + hTransform = cmsCreateTransform (in, TYPE_RGB_FLT, NULL, TYPE_Lab_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -3917,14 +3926,14 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam lcmsMutex->unlock (); - if (hTransform == nullptr) { + if (hTransform == NULL) { // Fallback: create transform from camera profile. Should not happen normally. lcmsMutex->lock (); hTransform = cmsCreateTransform (camprofile, TYPE_RGB_FLT, prophoto, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); lcmsMutex->unlock (); } - TMatrix toxyz, torgb; + TMatrix toxyz = {}, torgb = {}; if (!working_space_is_prophoto) { toxyz = iccStore->workingSpaceMatrix ("ProPhoto"); @@ -4127,8 +4136,8 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam // Determine RAW input and output profiles. Returns TRUE on success bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in) { - in = nullptr; // cam will be taken on NULL - *dcpProf = nullptr; + in = NULL; // cam will be taken on NULL + *dcpProf = NULL; if (inProfile == "(none)") { return false; @@ -4140,7 +4149,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed // DCPs have higher quality, so use them first *dcpProf = DCPStore::getInstance()->getStdProfile(camName); - if (*dcpProf == nullptr) { + if (*dcpProf == NULL) { in = iccStore->getStdProfile(camName); } } else if (inProfile != "(camera)" && inProfile != "") { @@ -4154,7 +4163,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed *dcpProf = DCPStore::getInstance()->getProfile(normalName); } - if (*dcpProf == nullptr) { + if (*dcpProf == NULL) { in = iccStore->getProfile (inProfile); } } @@ -4202,7 +4211,7 @@ void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int wi for (int col = 0; col < width; col++) { float rgb[ColorCount], cam[2][ColorCount], lab[2][ColorCount], sum[2], chratio, lratio = 0; - float L, C, H, Lfrac; + float L, C, H; // Copy input pixel to rgb so it's easier to access in loops rgb[0] = rin[col]; @@ -4290,7 +4299,7 @@ void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int wi bin[col] = L + H / 3.0; if ((L = (rin[col] + gin[col] + bin[col]) / 3) > desatpt) { - Lfrac = max(0.0f, (maxave - L) / (maxave - desatpt)); + float Lfrac = max(0.0f, (maxave - L) / (maxave - desatpt)); C = Lfrac * 1.732050808 * (rin[col] - gin[col]); H = Lfrac * (2 * bin[col] - rin[col] - gin[col]); rin[col] = L - H / 6.0 + C / 3.464101615; @@ -4887,11 +4896,11 @@ ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vectorgetSensorType() != ST_BAYER) { if(ri->getSensorType() == ST_FUJI_XTRANS) { int d[9][2] = {{0, 0}, { -1, -1}, { -1, 0}, { -1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; - double rloc, gloc, bloc; - int rnbrs, gnbrs, bnbrs; for (size_t i = 0; i < red.size(); i++) { transformPosition (red[i].x, red[i].y, tran, x, y); + double rloc, gloc, bloc; + int rnbrs, gnbrs, bnbrs; rloc = gloc = bloc = rnbrs = gnbrs = bnbrs = 0; for (int k = 0; k < 9; k++) { @@ -4959,11 +4968,11 @@ ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vectorget_rotateDegree(); diff --git a/rtengine/rawimagesource_i.h b/rtengine/rawimagesource_i.h index f5685b0ef..4e953becb 100644 --- a/rtengine/rawimagesource_i.h +++ b/rtengine/rawimagesource_i.h @@ -140,7 +140,7 @@ inline void RawImageSource::interpolate_row_g (float* agh, float* agv, int i) inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, float* cg, float* ng, int i) { - if (ri->ISRED(i, 0) || ri->ISRED(i, 1)) { + if ((ri->ISRED(i, 0) || ri->ISRED(i, 1)) && pg && ng) { // RGRGR or GRGRGR line for (int j = 0; j < W; j++) { if (ri->ISRED(i, j)) { @@ -172,7 +172,7 @@ inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, b = cg[j] + b / n; ab[j] = b; - } else { + } else if(ng && pg) { // linear R-G interp. horizontally int r; @@ -199,7 +199,7 @@ inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, ab[j] = b; } } - } else { + } else if(ng && pg) { // BGBGB or GBGBGB line for (int j = 0; j < W; j++) { if (ri->ISBLUE(i, j)) { @@ -265,7 +265,7 @@ inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, inline void RawImageSource::interpolate_row_rb_mul_pp (float* ar, float* ab, float* pg, float* cg, float* ng, int i, float r_mul, float g_mul, float b_mul, int x1, int width, int skip) { - if (ri->ISRED(i, 0) || ri->ISRED(i, 1)) { + if ((ri->ISRED(i, 0) || ri->ISRED(i, 1)) && pg && ng) { // RGRGR or GRGRGR line for (int j = x1, jx = 0; jx < width; j += skip, jx++) { if (ri->ISRED(i, j)) { @@ -324,7 +324,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (float* ar, float* ab, flo ab[jx] = b; } } - } else { + } else if(pg && ng) { // BGBGB or GBGBGB line for (int j = x1, jx = 0; jx < width; j += skip, jx++) { if (ri->ISBLUE(i, j)) { diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 5175836e4..025265e0a 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -119,8 +119,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { ALLNORAW, // EvDPDNLuma, ALLNORAW, // EvDPDNChroma, ALLNORAW, // EvDPDNGamma, - ALLNORAW, // EvDirPyrEqualizer, - ALLNORAW, // EvDirPyrEqlEnabled, + ALLNORAW, // EvDirPyrEqualizer, + ALLNORAW, // EvDirPyrEqlEnabled, LUMINANCECURVE, // EvLSaturation, LUMINANCECURVE, // EvLaCurve, LUMINANCECURVE, // EvLbCurve, @@ -275,12 +275,12 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, // EvLCLCurve LUMINANCECURVE, // EvLLHCurve LUMINANCECURVE, // EvLHHCurve - ALLNORAW, // EvDirPyrEqualizerThreshold + ALLNORAW, // EvDirPyrEqualizerThreshold ALLNORAW, // EvDPDNenhance RGBCURVE, // EvBWMethodalg - ALLNORAW, // EvDirPyrEqualizerSkin - ALLNORAW, // EvDirPyrEqlgamutlab - ALLNORAW, // EvDirPyrEqualizerHueskin + ALLNORAW, // EvDirPyrEqualizerSkin + ALLNORAW, // EvDirPyrEqlgamutlab + ALLNORAW, // EvDirPyrEqualizerHueskin ALLNORAW, // EvDPDNmedian ALLNORAW, // EvDPDNmedmet RGBCURVE, // EvColorToningEnabled @@ -453,7 +453,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLhighl DEMOSAIC, // EvLbaselog DEMOSAIC, // EvRetinexlhcurve - ALLNORAW, // EvOIntent + OUTPUTPROFILE, // EvOIntent MONITORTRANSFORM, // EvMonitorTransform: no history message RETINEX, // EvLiter RETINEX, // EvLgrad @@ -465,10 +465,11 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLradius RETINEX, // EvmapMethod DEMOSAIC, // EvRetinexmapcurve - DEMOSAIC, // EvviewMethod - ALLNORAW, // EvcbdlMethod + DEMOSAIC, // EvviewMethod + ALLNORAW, // EvcbdlMethod RETINEX, // EvRetinexgaintransmission - RETINEX //EvLskal + RETINEX, // EvLskal + OUTPUTPROFILE // EvOBPCompens }; diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 23e179f9f..e262c9394 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -46,7 +46,7 @@ // Bitfield of functions to do to the preview image when an event occurs // Use those or create new ones for your new events -#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL +#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR|M_MONITOR) // without HIGHQUAL #define ALL (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL #define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define FLATFIELD (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) @@ -61,7 +61,7 @@ #define DEFRINGE (M_LUMINANCE|M_COLOR) #define DIRPYRDENOISE (M_LUMINANCE|M_COLOR) #define DIRPYREQUALIZER (M_LUMINANCE|M_COLOR) -#define GAMMA (M_LUMINANCE|M_COLOR) +#define GAMMA M_MONITOR #define CROP M_CROP #define RESIZE M_VOID #define EXIF M_VOID @@ -69,7 +69,7 @@ #define MINUPDATE M_MINUPDATE #define RETINEX (M_RETINEX|ALLNORAW) #define MONITORTRANSFORM M_MONITOR -#define OUTPUTPROFILE (ALLNORAW|MONITORTRANSFORM) +#define OUTPUTPROFILE M_MONITOR extern int refreshmap[]; #endif diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 10a42a0d5..61c779fb7 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -418,6 +418,8 @@ public: virtual void setMonitorProfile (const Glib::ustring& monitorProfile, RenderingIntent intent) = 0; virtual void getMonitorProfile (Glib::ustring& monitorProfile, RenderingIntent& intent) const = 0; + virtual void setSoftProofing (bool softProof, bool gamutCheck) = 0; + virtual void getSoftProofing (bool &softProof, bool &gamutCheck) = 0; virtual ~StagedImageProcessor () {} diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 7c6aa5b5b..c135acc39 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -735,6 +735,7 @@ void Thumbnail::init () } Thumbnail::Thumbnail () : + iColorMatrix{}, cam2xyz{}, scale(1.0), colorMatrix{}, isRaw(true), camProfile(nullptr), thumbImg(nullptr), camwbRed(1.0), camwbGreen(1.0), camwbBlue(1.0), redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), @@ -908,7 +909,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei ImProcFunctions ipf (¶ms, false); ipf.setScale (sqrt(double(fw * fw + fh * fh)) / sqrt(double(thumbImg->width * thumbImg->width + thumbImg->height * thumbImg->height))*scale); - ipf.updateColorProfiles (params.icm, options.rtSettings.monitorProfile, options.rtSettings.monitorIntent); + ipf.updateColorProfiles (params.icm, options.rtSettings.monitorProfile, options.rtSettings.monitorIntent, false, false); LUTu hist16 (65536); diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index bc367522d..18e72fc19 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -107,7 +107,7 @@ public: static ImageIO* resizeToSameType(int nw, int nh, TypeInterpolation interp, ImageIO* srcImg) { - ImageIO* imgPtr; + ImageIO* imgPtr = nullptr; if (srcImg->getType() == sImage8) { Image8* castedSrcImg = static_cast(srcImg); diff --git a/rtengine/settings.h b/rtengine/settings.h index 8810322be..b572e7310 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -40,6 +40,7 @@ public: Glib::ustring monitorProfile; ///< ICC profile name used for the monitor RenderingIntent monitorIntent; ///< Colorimetric intent used with the above profile + bool monitorBPC; ///< Black Point Compensation for the Labimage->Monitor transform (directly, i.e. not soft-proofing and no WCS in between) bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile bool autocielab; bool rgbcurveslumamode_gamut;// controls gamut enforcement for RGB curves in lumamode diff --git a/rtengine/shmap.cc b/rtengine/shmap.cc index bb8e96c11..65c1070a2 100644 --- a/rtengine/shmap.cc +++ b/rtengine/shmap.cc @@ -30,7 +30,7 @@ namespace rtengine extern const Settings* settings; -SHMap::SHMap (int w, int h, bool multiThread) : W(w), H(h), multiThread(multiThread) +SHMap::SHMap (int w, int h, bool multiThread) : max_f(0.f), min_f(0.f), avg(0.f), W(w), H(h), multiThread(multiThread) { map = new float*[H]; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index acdeb5133..e31103929 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -54,7 +54,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p if (errorCode) { delete job; - return nullptr; + return NULL; } } @@ -165,7 +165,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p NoiseCurve noiseLCurve; NoiseCurve noiseCCurve; - Imagefloat *calclum = nullptr ; + Imagefloat *calclum = NULL ; params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve); float autoNR = (float) settings->nrauto;// float autoNRmax = (float) settings->nrautomax;// @@ -754,7 +754,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } // update blurmap - SHMap* shmap = nullptr; + SHMap* shmap = NULL; if (params.sh.enabled) { shmap = new SHMap (fw, fh, true); @@ -858,7 +858,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p DCPProfile::ApplyState as; DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); - ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as); + ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as); if (settings->verbose) { printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); @@ -881,13 +881,13 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // Freeing baseImg because not used anymore delete baseImg; - baseImg = nullptr; + baseImg = NULL; if (shmap) { delete shmap; } - shmap = nullptr; + shmap = NULL; if (pl) { pl->setProgress (0.55); @@ -933,7 +933,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 1); - ipf.chromiLuminanceCurve (nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); + ipf.chromiLuminanceCurve (NULL, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { ipf.EPDToneMap(labView, 5, 1); @@ -1071,7 +1071,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } delete cieView; - cieView = nullptr; + cieView = NULL; @@ -1147,217 +1147,31 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } } - Image16* readyImg = nullptr; - cmsHPROFILE jprof = nullptr; + Image16* readyImg = NULL; + cmsHPROFILE jprof = NULL; bool customGamma = false; bool useLCMS = false; + bool bwonly = params.blackwhite.enabled && !params.colorToning.enabled && !autili && !butili ; if(params.icm.gamma != "default" || params.icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 - double ga0, ga1, ga2, ga3, ga4, ga5, ga6; + GammaValues ga; // if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; - readyImg = ipf.lab2rgb16b (labView, cx, cy, cw, ch, params.icm.output, params.icm.outputIntent, params.icm.working, params.icm.gamma, params.icm.freegamma, params.icm.gampos, params.icm.slpos, ga0, ga1, ga2, ga3, ga4, ga5, ga6, params.blackwhite.enabled ); + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly, &ga); customGamma = true; //or selected Free gamma useLCMS = false; - bool pro = false; - Glib::ustring chpro, outProfile; - bool present_space[10] = {false, false, false, false, false, false, false, false, false, false}; - std::vector opnames = iccStore->getProfiles (); - - //test if files are in system - for (int j = 0; j < 10; j++) { - // one can modify "option" [Color Management] to adapt the profile's name if they are different for windows, MacOS, Linux ?? - // some of them are actually provided by RT, thanks to Jacques Desmis - if (j == 0) { - chpro = options.rtSettings.prophoto; - } else if(j == 1) { - chpro = options.rtSettings.adobe; - } else if(j == 2) { - chpro = options.rtSettings.widegamut; - } else if(j == 3) { - chpro = options.rtSettings.beta; - } else if(j == 4) { - chpro = options.rtSettings.best; - } else if(j == 5) { - chpro = options.rtSettings.bruce; - } else if(j == 6) { - chpro = options.rtSettings.srgb; - } else if(j == 7) { - chpro = options.rtSettings.srgb10; //gamma 1.0 - } else if(j == 8) { - chpro = options.rtSettings.prophoto10; //gamma 1.0 - } else if(j == 9) { - chpro = options.rtSettings.rec2020; - } - - for (unsigned int i = 0; i < opnames.size(); i++) { - if(chpro.compare(opnames[i]) == 0) { - present_space[j] = true; - } - } - - if (!present_space[j] && settings->verbose) { - printf("Missing file: %s\n", chpro.c_str()); - } - } - - if (params.icm.freegamma && params.icm.gampos < 1.35) { - pro = true; //select profil with gammaTRC modified : - } else if (params.icm.gamma == "linear_g1.0" || (params.icm.gamma == "High_g1.3_s3.35")) { - pro = true; //pro=0 RT_sRGB || Prophoto - } - - // Check that output profiles exist, otherwise use LCMS2 - // Use the icc/icm profiles associated to possible working profiles, set in "options" - if (params.icm.working == "ProPhoto" && present_space[0] && !pro) { - outProfile = options.rtSettings.prophoto; - } else if (params.icm.working == "Adobe RGB" && present_space[1] ) { - outProfile = options.rtSettings.adobe; - } else if (params.icm.working == "WideGamut" && present_space[2] ) { - outProfile = options.rtSettings.widegamut; - } else if (params.icm.working == "Beta RGB" && present_space[3] ) { - outProfile = options.rtSettings.beta; - } else if (params.icm.working == "BestRGB" && present_space[4] ) { - outProfile = options.rtSettings.best; - } else if (params.icm.working == "BruceRGB" && present_space[5] ) { - outProfile = options.rtSettings.bruce; - } else if (params.icm.working == "sRGB" && present_space[6] && !pro) { - outProfile = options.rtSettings.srgb; - } else if (params.icm.working == "sRGB" && present_space[7] && pro) { - outProfile = options.rtSettings.srgb10; - } else if (params.icm.working == "ProPhoto" && present_space[8] && pro) { - outProfile = options.rtSettings.prophoto10; - } else if (params.icm.working == "Rec2020" && present_space[9]) { - outProfile = options.rtSettings.rec2020; - } else { - // Should not occurs - if (settings->verbose) { - printf("\"%s\": unknown working profile! - use LCMS2 substitution\n", params.icm.working.c_str() ); - } + if ((jprof = iccStore->createCustomGammaOutputProfile (params.icm, ga)) == NULL) { useLCMS = true; } - //begin adaptation rTRC gTRC bTRC - //"jprof" profile has the same characteristics than RGB values, but TRC are adapted... for applying profile - if (!useLCMS) { - if (settings->verbose) { - printf("Output Gamma - profile: \"%s\"\n", outProfile.c_str() ); //c_str() - } - - jprof = iccStore->getProfile(outProfile); //get output profile - - if (jprof == nullptr) { - useLCMS = true; - - if (settings->verbose) { - printf("\"%s\" ICC output profile not found!\n", outProfile.c_str()); - } - } else { - cmsToneCurve* GammaTRC[3] = { nullptr, nullptr, nullptr }; - - cmsFloat64Number Parameters[7]; - - Parameters[0] = ga0; - Parameters[1] = ga1; - Parameters[2] = ga2; - Parameters[3] = ga3; - Parameters[4] = ga4; - Parameters[5] = ga5; - Parameters[6] = ga6; - // 7 parameters for smoother curves - //change desc Tag , to "free gamma", or "BT709", etc. - cmsMLU *DescriptionMLU, *CopyrightMLU, *DmndMLU, *DmddMLU;// for modification TAG - - cmsContext ContextID = cmsGetProfileContextID(jprof);//modification TAG - DescriptionMLU = cmsMLUalloc(ContextID, 1); - CopyrightMLU = cmsMLUalloc(ContextID, 1);//for ICC - DmndMLU = cmsMLUalloc(ContextID, 1); //for ICC - DmddMLU = cmsMLUalloc(ContextID, 1); // for ICC - - - // instruction with //ICC are used for generate icc profile - if (DescriptionMLU == nullptr) { - printf("Description error\n"); - } - - cmsMLUsetWide(CopyrightMLU, "en", "US", L"General Public License - AdobeRGB compatible") ;//adapt to profil - cmsMLUsetWide(DmndMLU, "en", "US", L"RawTherapee") ; - cmsMLUsetWide(DmddMLU, "en", "US", L"RTMedium") ; //adapt to profil - - //display Tag desc with : selection of gamma and Primaries - if (!params.icm.freegamma) { - std::wstring gammaStr; - - if(params.icm.gamma == "High_g1.3_s3.35") { - gammaStr = std::wstring(L"GammaTRC: High g=1.3 s=3.35"); - } else if (params.icm.gamma == "Low_g2.6_s6.9") { - gammaStr = std::wstring(L"GammaTRC: Low g=2.6 s=6.9"); - } else if (params.icm.gamma == "sRGB_g2.4_s12.92") { - gammaStr = std::wstring(L"GammaTRC: sRGB g=2.4 s=12.92"); - } else if (params.icm.gamma == "BT709_g2.2_s4.5") { - gammaStr = std::wstring(L"GammaTRC: BT709 g=2.2 s=4.5"); - } else if (params.icm.gamma == "linear_g1.0") { - gammaStr = std::wstring(L"GammaTRC: Linear g=1.0"); - } else if (params.icm.gamma == "standard_g2.2") { - gammaStr = std::wstring(L"GammaTRC: g=2.2"); - } else if (params.icm.gamma == "standard_g1.8") { - gammaStr = std::wstring(L"GammaTRC: g=1.8"); - } - - cmsMLUsetWide(DescriptionMLU, "en", "US", gammaStr.c_str()); - - //for elaboration ICC profiles - // else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Medium gamma sRGB(AdobeRGB compatible)"); - // else if (params.icm.gamma== "BT709_g2.2_s4.5" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma BT709(IEC61966 equivalent)"); - // else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma sRGB(IEC61966 equivalent)"); - // else if (params.icm.gamma== "linear_g1.0" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma Linear1.0(IEC61966 equivalent)"); - //else if (params.icm.gamma== "BT709_g2.2_s4.5" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma BT709(Prophoto compatible)"); - // else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma sRGB(Prophoto compatible)"); - // else if (params.icm.gamma== "linear_g1.0" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma Linear1.0(Prophoto compatible)"); - } else { - // create description with gamma + slope + primaries - std::wostringstream gammaWs; - gammaWs.precision(2); - gammaWs << "Manual GammaTRC: g=" << (float)params.icm.gampos << " s=" << (float)params.icm.slpos; - cmsMLUsetWide(DescriptionMLU, "en", "US", gammaWs.str().c_str()); - } - - cmsWriteTag(jprof, cmsSigProfileDescriptionTag, DescriptionMLU);//desc changed - // cmsWriteTag(jprof, cmsSigCopyrightTag, CopyrightMLU); - // cmsWriteTag(jprof, cmsSigDeviceMfgDescTag, DmndMLU); - // cmsWriteTag(jprof, cmsSigDeviceModelDescTag, DmddMLU); - - // Calculate output profile's rTRC bTRC gTRC - GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(nullptr, 5, Parameters); - cmsWriteTag(jprof, cmsSigGreenTRCTag, (void*)GammaTRC[1] ); - cmsWriteTag(jprof, cmsSigRedTRCTag, (void*)GammaTRC[0] ); - cmsWriteTag(jprof, cmsSigBlueTRCTag, (void*)GammaTRC[2] ); - //for generation ICC profiles : here Prophoto ==> Large - // if(params.icm.gamma== "BT709_g2.2_s4.5") cmsSaveProfileToFile(jprof, "RT_sRGB_gBT709.icm"); - // else if (params.icm.gamma== "sRGB_g2.4_s12.92") cmsSaveProfileToFile(jprof, "RT_Medium_gsRGB.icc"); - // else if (params.icm.gamma== "linear_g1.0") cmsSaveProfileToFile(jprof, "RT_Large_g10.icc"); - - if (GammaTRC[0]) { - cmsFreeToneCurve(GammaTRC[0]); - } - } - } - } else { // if Default gamma mode: we use the profile selected in the "Output profile" combobox; // gamma come from the selected profile, otherwise it comes from "Free gamma" tool - // readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, params.blackwhite.enabled); - bool bwonly = params.blackwhite.enabled && !params.colorToning.enabled ; - - if(autili || butili ) { - bwonly = false; - } - - readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, params.icm.outputIntent, bwonly); + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly); if (settings->verbose) { printf("Output profile_: \"%s\"\n", params.icm.output.c_str()); @@ -1365,21 +1179,19 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } delete labView; - labView = nullptr; + labView = NULL; - if(!autili && !butili ) { - if(params.blackwhite.enabled && !params.colorToning.enabled ) {//force BW r=g=b - if (settings->verbose) { - printf("Force BW\n"); - } + if(bwonly) { //force BW r=g=b + if (settings->verbose) { + printf("Force BW\n"); + } - for (int ccw = 0; ccw < cw; ccw++) { - for (int cch = 0; cch < ch; cch++) { - readyImg->r(cch, ccw) = readyImg->g(cch, ccw); - readyImg->b(cch, ccw) = readyImg->g(cch, ccw); - } + for (int ccw = 0; ccw < cw; ccw++) { + for (int cch = 0; cch < ch; cch++) { + readyImg->r(cch, ccw) = readyImg->g(cch, ccw); + readyImg->b(cch, ccw) = readyImg->g(cch, ccw); } } } @@ -1405,42 +1217,33 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // Setting the output curve to readyImg if (customGamma) { if (!useLCMS) { - // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16b + // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16 w/ gamma ProfileContent pc(jprof); readyImg->setOutputProfile (pc.data, pc.length); } } else { - // use RT_sRGB.icm profile if present, otherwise use LCMS2 profile generate by lab2rgb16b - Glib::ustring outputProfile; + // use the selected output profile if present, otherwise use LCMS2 profile generate by lab2rgb16 w/ gamma if (params.icm.output != "" && params.icm.output != ColorManagementParams::NoICMString) { - outputProfile = params.icm.output; - - /* if we'd wanted the RT_sRGB profile we would have selected it - else { - // use RT_sRGB.icm profile if present, otherwise use LCMS2 profile generate by lab2rgb16b - if (settings->verbose) printf("No output profiles set ; looking for the default sRGB profile (\"%s\")...\n", options.rtSettings.srgb.c_str()); - outputProfile = options.rtSettings.srgb; - }*/ // if iccStore->getProfile send back an object, then iccStore->getContent will do too - cmsHPROFILE jprof = iccStore->getProfile(outputProfile); //get outProfile + cmsHPROFILE jprof = iccStore->getProfile(params.icm.output); //get outProfile - if (jprof == nullptr) { + if (jprof == NULL) { if (settings->verbose) { - printf("\"%s\" ICC output profile not found!\n - use LCMS2 substitution\n", outputProfile.c_str()); + printf("\"%s\" ICC output profile not found!\n - use LCMS2 substitution\n", params.icm.output.c_str()); } } else { if (settings->verbose) { - printf("Using \"%s\" output profile\n", outputProfile.c_str()); + printf("Using \"%s\" output profile\n", params.icm.output.c_str()); } - ProfileContent pc = iccStore->getContent (outputProfile); + ProfileContent pc = iccStore->getContent (params.icm.output); readyImg->setOutputProfile (pc.data, pc.length); } } else { // No ICM - readyImg->setOutputProfile (nullptr, 0); + readyImg->setOutputProfile (NULL, 0); } } @@ -1483,13 +1286,13 @@ void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl, bo if (errorCode) { bpl->error (M("MAIN_MSG_CANNOTLOAD")); - currentJob = nullptr; + currentJob = NULL; } else { try { currentJob = bpl->imageReady (img); } catch (Glib::Exception& ex) { bpl->error (ex.what()); - currentJob = nullptr; + currentJob = NULL; } } } diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 128bfdfa9..826c8a49b 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -51,15 +51,11 @@ template T** allocArray (int W, int H) } #define HR_SCALE 2 -StdImageSource::StdImageSource () : ImageSource(), img(nullptr), plistener(nullptr) +StdImageSource::StdImageSource () : ImageSource(), img(NULL), plistener(NULL), full(false), max{}, rgbSourceModified(false) { - hrmap[0] = nullptr; - hrmap[1] = nullptr; - hrmap[2] = nullptr; - needhr = nullptr; - embProfile = nullptr; - idata = nullptr; + embProfile = NULL; + idata = NULL; } StdImageSource::~StdImageSource () @@ -67,17 +63,6 @@ StdImageSource::~StdImageSource () delete idata; - if (hrmap[0] != nullptr) { - int dh = img->getH() / HR_SCALE; - freeArray(hrmap[0], dh); - freeArray(hrmap[1], dh); - freeArray(hrmap[2], dh); - } - - if (needhr) { - freeArray(needhr, img->getH()); - } - if (img) { delete img; } @@ -178,7 +163,7 @@ int StdImageSource::load (const Glib::ustring &fname, bool batch) if (error) { delete img; - img = nullptr; + img = NULL; return error; } @@ -243,7 +228,7 @@ void StdImageSource::colorSpaceConversion (Imagefloat* im, const ColorManagement { bool skipTransform = false; - cmsHPROFILE in = nullptr; + cmsHPROFILE in = NULL; cmsHPROFILE out = iccStore->workingSpace (cmp.working); if (cmp.input == "(embedded)" || cmp.input == "" || cmp.input == "(camera)" || cmp.input == "(cameraICC)") { @@ -260,9 +245,9 @@ void StdImageSource::colorSpaceConversion (Imagefloat* im, const ColorManagement if (cmp.input != "(none)") { in = iccStore->getProfile (cmp.input); - if (in == nullptr && embedded) { + if (in == NULL && embedded) { in = embedded; - } else if (in == nullptr) { + } else if (in == NULL) { if (sampleFormat & (IIOSF_LOGLUV24 | IIOSF_LOGLUV32 | IIOSF_FLOAT)) { skipTransform = true; } else { @@ -311,7 +296,7 @@ void StdImageSource::getFullSize (int& w, int& h, int tr) } } -void StdImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) +void StdImageSource::getSize (PreviewProps pp, int& w, int& h) { w = pp.w / pp.skip + (pp.w % pp.skip > 0); diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index e6ecf80a7..0ef487a75 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -32,8 +32,6 @@ protected: ColorTemp wb; ProgressListener* plistener; bool full; - float** hrmap[3]; - char** needhr; int max[3]; bool rgbSourceModified; @@ -66,7 +64,7 @@ public: } void getFullSize (int& w, int& h, int tr = TR_NONE); - void getSize (int tran, PreviewProps pp, int& w, int& h); + void getSize (PreviewProps pp, int& w, int& h); ImageData* getImageData () { diff --git a/rtengine/utils.cc b/rtengine/utils.cc index 2366f3a0c..b862e290f 100644 --- a/rtengine/utils.cc +++ b/rtengine/utils.cc @@ -168,9 +168,7 @@ void rotate (unsigned char* img, int& w, int& h, int deg) rotated[3 * (j * h + h - i - 1) + 2] = img[ix++]; } - int tmp = w; - w = h; - h = tmp; + std::swap(w,h); } else if (deg == 270) { for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) { @@ -179,10 +177,8 @@ void rotate (unsigned char* img, int& w, int& h, int deg) rotated[3 * (h * (w - j - 1) + i) + 2] = img[ix++]; } - int tmp = w; - w = h; - h = tmp; - } else if (deg == 180) + std::swap(w,h); + } else /*if (deg == 180) */ for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) { rotated[3 * (w * (h - i - 1) + w - j - 1) + 0] = img[ix++]; diff --git a/rtgui/curveeditorgroup.cc b/rtgui/curveeditorgroup.cc index 71f94db4b..ecb4c8542 100644 --- a/rtgui/curveeditorgroup.cc +++ b/rtgui/curveeditorgroup.cc @@ -355,7 +355,7 @@ void CurveEditorGroup::setTooltip( Glib::ustring ttip) void CurveEditorGroup::setBatchMode (bool batchMode) { for (std::vector::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) { - (*i)->curveType->addEntry("curveType-unchanged.png", M("GENERAL_UNCHANGED")); + (*i)->curveType->addEntry("unchanged-18.png", M("GENERAL_UNCHANGED")); (*i)->curveType->show(); } } diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index fb3d51297..8abbe6e27 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -35,11 +35,13 @@ using namespace rtengine::procparams; -class EditorPanel::MonitorProfileSelector +class EditorPanel::ColorManagementToolbar { private: MyComboBoxText profileBox; PopUpButton intentBox; + Gtk::ToggleButton softProof; + Gtk::ToggleButton spGamutCheck; sigc::connection profileConn, intentConn; rtengine::StagedImageProcessor* const& processor; @@ -57,27 +59,49 @@ private: profileBox.set_active (0); #endif - const std::vector profiles = rtengine::iccStore->getProfiles (); + const std::vector profiles = rtengine::iccStore->getProfiles (true); for (std::vector::const_iterator iterator = profiles.begin (); iterator != profiles.end (); ++iterator) { profileBox.append_text (*iterator); } + profileBox.set_tooltip_text (profileBox.get_active_text ()); } void prepareIntentBox () { - intentBox.addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); + // same order as the enum intentBox.addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); + intentBox.addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); intentBox.addEntry("intent-absolute.png", M("PREFERENCES_INTENT_ABSOLUTE")); - intentBox.setSelected(0); + intentBox.setSelected(1); intentBox.show (); } + void prepareSoftProofingBox () + { + Gtk::Image *softProofImage = Gtk::manage (new RTImage ("softProof.png")); + softProofImage->set_padding(0, 0); + softProof.add(*softProofImage); + softProof.set_relief(Gtk::RELIEF_NONE); + softProof.set_tooltip_markup(M("SOFTPROOF_TOOLTIP")); + + softProof.set_active(false); + softProof.show (); + + Gtk::Image *spGamutCheckImage = Gtk::manage (new RTImage ("spGamutCheck.png")); + spGamutCheckImage->set_padding(0, 0); + spGamutCheck.add(*spGamutCheckImage); + spGamutCheck.set_relief(Gtk::RELIEF_NONE); + spGamutCheck.set_tooltip_markup(M("SOFTPROOF_GAMUTCHECK_TOOLTIP")); + + spGamutCheck.set_active(false); + spGamutCheck.set_sensitive(false); + spGamutCheck.show (); + } + void profileBoxChanged () { updateParameters (); - - profileBox.set_tooltip_text (profileBox.get_active_text ()); } void intentBoxChanged (int) @@ -85,7 +109,17 @@ private: updateParameters (); } - void updateParameters () + void softProofToggled () + { + updateSoftProofParameters (); + } + + void spGamutCheckToggled () + { + updateSoftProofParameters (); + } + + void updateParameters (bool noEvent = false) { ConnectionBlocker profileBlocker (profileConn); ConnectionBlocker intentBlocker (intentConn); @@ -113,33 +147,46 @@ private: profile.clear(); intentBox.set_sensitive (false); - intentBox.setSelected (0); + intentBox.setSelected (1); + softProof.set_sensitive(false); + spGamutCheck.set_sensitive(false); + + profileBox.set_tooltip_text (""); } else { - const std::uint8_t supportedIntents = rtengine::iccStore->getProofIntents (profile); + const uint8_t supportedIntents = rtengine::iccStore->getProofIntents (profile); const bool supportsRelativeColorimetric = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; const bool supportsAbsoluteColorimetric = supportedIntents & 1 << INTENT_ABSOLUTE_COLORIMETRIC; if (supportsPerceptual || supportsRelativeColorimetric || supportsAbsoluteColorimetric) { intentBox.set_sensitive (true); - intentBox.setItemSensitivity(0, supportsRelativeColorimetric); - intentBox.setItemSensitivity(1, supportsPerceptual); + intentBox.setItemSensitivity(0, supportsPerceptual); + intentBox.setItemSensitivity(1, supportsRelativeColorimetric); intentBox.setItemSensitivity(2, supportsAbsoluteColorimetric); + softProof.set_sensitive(true); + spGamutCheck.set_sensitive(true); } else { + intentBox.setItemSensitivity(0, true); + intentBox.setItemSensitivity(1, true); + intentBox.setItemSensitivity(2, true); intentBox.set_sensitive (false); - intentBox.setSelected (0); + intentBox.setSelected (1); + softProof.set_sensitive(false); + spGamutCheck.set_sensitive(false); } + + profileBox.set_tooltip_text (profileBox.get_active_text ()); } rtengine::RenderingIntent intent; switch (intentBox.getSelected ()) { default: case 0: - intent = rtengine::RI_RELATIVE; + intent = rtengine::RI_PERCEPTUAL; break; case 1: - intent = rtengine::RI_PERCEPTUAL; + intent = rtengine::RI_RELATIVE; break; case 2: intent = rtengine::RI_ABSOLUTE; @@ -150,31 +197,63 @@ private: return; } - processor->beginUpdateParams (); + if (!noEvent) { + processor->beginUpdateParams (); + } processor->setMonitorProfile (profile, intent); - processor->endUpdateParams (rtengine::EvMonitorTransform); + processor->setSoftProofing (softProof.get_sensitive() && softProof.get_active(), spGamutCheck.get_sensitive() && spGamutCheck.get_active()); + if (!noEvent) { + processor->endUpdateParams (rtengine::EvMonitorTransform); + } + } + + void updateSoftProofParameters (bool noEvent = false) + { + spGamutCheck.set_sensitive(softProof.get_active()); + + if (profileBox.get_active_row_number () > 0) { + if (!noEvent) { + processor->beginUpdateParams (); + } + processor->setSoftProofing (softProof.get_sensitive() && softProof.get_active(), spGamutCheck.get_sensitive() && spGamutCheck.get_active()); + if (!noEvent) { + processor->endUpdateParams (rtengine::EvMonitorTransform); + } + } } public: - explicit MonitorProfileSelector (rtengine::StagedImageProcessor* const& ipc) : + explicit ColorManagementToolbar (rtengine::StagedImageProcessor* const& ipc) : intentBox (Glib::ustring (), true), processor (ipc) { prepareProfileBox (); prepareIntentBox (); + prepareSoftProofingBox (); reset (); - profileConn = profileBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::profileBoxChanged)); - intentConn = intentBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::intentBoxChanged)); + softProof.signal_toggled().connect(sigc::mem_fun (this, &ColorManagementToolbar::softProofToggled)); + spGamutCheck.signal_toggled().connect(sigc::mem_fun (this, &ColorManagementToolbar::spGamutCheckToggled));; + profileConn = profileBox.signal_changed ().connect (sigc::mem_fun (this, &ColorManagementToolbar::profileBoxChanged)); + intentConn = intentBox.signal_changed ().connect (sigc::mem_fun (this, &ColorManagementToolbar::intentBoxChanged)); } void pack_end_in (Gtk::Box* box) { + box->pack_end (spGamutCheck, Gtk::PACK_SHRINK, 0); + box->pack_end (softProof, Gtk::PACK_SHRINK, 0); box->pack_end (*intentBox.buttonGroup, Gtk::PACK_SHRINK, 0); box->pack_end (profileBox, Gtk::PACK_SHRINK, 0); } + void updateProcessor() + { + if (processor) { + updateParameters(true); + } + } + void reset () { ConnectionBlocker profileBlocker (profileConn); @@ -193,10 +272,10 @@ public: switch (options.rtSettings.monitorIntent) { default: - case rtengine::RI_RELATIVE: + case rtengine::RI_PERCEPTUAL: intentBox.setSelected (0); break; - case rtengine::RI_PERCEPTUAL: + case rtengine::RI_RELATIVE: intentBox.setSelected (1); break; case rtengine::RI_ABSOLUTE: @@ -444,9 +523,9 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iops->pack_end (*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_SHRINK, 0); - // Monitor profile buttons - monitorProfile.reset (new MonitorProfileSelector (ipc)); - monitorProfile->pack_end_in (iops); + // Color management toolbar + colorMgmtToolBar.reset (new ColorManagementToolbar (ipc)); + colorMgmtToolBar->pack_end_in (iops); editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0); editbox->pack_start (*iops, Gtk::PACK_SHRINK, 0); @@ -706,6 +785,7 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) this->isrc = isrc; ipc = rtengine::StagedImageProcessor::create (isrc); ipc->setProgressListener (this); + colorMgmtToolBar->updateProcessor(); ipc->setPreviewImageListener (previewHandler); ipc->setPreviewScale (10); // Important tpc->initImage (ipc, tmb->getType() == FT_Raw); @@ -754,8 +834,6 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) } history->resetSnapShotNumber(); - - monitorProfile->reset (); } void EditorPanel::close () diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 765739836..ac2be9566 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -84,8 +84,8 @@ protected: Gtk::Button* navNext; Gtk::Button* navPrev; - class MonitorProfileSelector; - std::unique_ptr monitorProfile; + class ColorManagementToolbar; + std::unique_ptr colorMgmtToolBar; ImageAreaPanel* iareapanel; PreviewHandler* previewHandler; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 82e3a0200..0c58b3038 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1176,6 +1176,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.icm.working = options.fastexport_icm_working ; params.icm.output = options.fastexport_icm_output ; params.icm.outputIntent = options.fastexport_icm_outputIntent ; + params.icm.outputBPC = options.fastexport_icm_outputBPC ; params.icm.gamma = options.fastexport_icm_gamma ; params.resize.enabled = options.fastexport_resize_enabled ; params.resize.scale = options.fastexport_resize_scale ; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 25e083af3..f674b8951 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -26,9 +26,9 @@ #include "../rtengine/improccoordinator.h" #include "../rtengine/color.h" #include "../rtengine/opthelper.h" +#include "../rtengine/iccstore.h" using namespace rtengine; -extern Glib::ustring argv0; extern Options options; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 884bc3e40..68663ed7e 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -193,15 +193,21 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch Gtk::HBox *riHBox = Gtk::manage ( new Gtk::HBox()); Gtk::Label* outputIntentLbl = Gtk::manage (new Gtk::Label(M("TP_ICM_PROFILEINTENT")+":")); riHBox->pack_start (*outputIntentLbl, Gtk::PACK_SHRINK); - ointent = Gtk::manage (new MyComboBoxText ()); - riHBox->pack_start (*ointent, Gtk::PACK_EXPAND_WIDGET); - ointent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); - ointent->append_text (M("PREFERENCES_INTENT_RELATIVE")); - ointent->append_text (M("PREFERENCES_INTENT_SATURATION")); - ointent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); - ointent->set_active (1); + ointent = Gtk::manage (new PopUpButton ()); + ointent->addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); + ointent->addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); + ointent->addEntry("intent-saturation.png", M("PREFERENCES_INTENT_SATURATION")); + ointent->addEntry("intent-absolute.png", M("PREFERENCES_INTENT_ABSOLUTE")); + ointent->setSelected (1); + ointent->show(); + riHBox->pack_start (*ointent->buttonGroup, Gtk::PACK_EXPAND_PADDING); oVBox->pack_start(*riHBox, Gtk::PACK_SHRINK); + // Black Point Compensation + obpc = Gtk::manage(new Gtk::CheckButton((M("TP_ICM_BPC")))); + obpc->set_active (true); + oVBox->pack_start(*obpc, Gtk::PACK_SHRINK); + // Output gamma Gtk::HBox* gaHBox = Gtk::manage (new Gtk::HBox ()); @@ -295,6 +301,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) ); dcpIll->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::dcpIlluminantChanged) ); + obpcconn = obpc->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::oBPCChanged) ); gamcsconn = freegamma->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::GamChanged)); tcurveconn = ckbToneCurve->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::toneCurveChanged)); ltableconn = ckbApplyLookTable->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::applyLookTableChanged)); @@ -313,6 +320,31 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch show_all (); } +void ICMPanel::updateRenderingIntent (const Glib::ustring &profile) { + const uint8_t supportedIntents = rtengine::iccStore->getOutputIntents (profile); + const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; + const bool supportsRelative = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; + const bool supportsSaturation = supportedIntents & 1 << INTENT_SATURATION; + const bool supportsAbsolute = supportedIntents & 1 << INTENT_ABSOLUTE_COLORIMETRIC; + + //printf("Intents: %d / Perceptual: %d Relative: %d Saturation: %d Absolute: %d\n", supportedIntents, supportsPerceptual, supportsRelative, supportsSaturation, supportsAbsolute); + + if (!profile.empty() && (supportsPerceptual || supportsRelative || supportsSaturation || supportsAbsolute)) { + ointent->set_sensitive (true); + ointent->setItemSensitivity(0, supportsPerceptual); + ointent->setItemSensitivity(1, supportsRelative); + ointent->setItemSensitivity(2, supportsSaturation); + ointent->setItemSensitivity(3, supportsAbsolute); + } else { + ointent->setItemSensitivity(0, true); + ointent->setItemSensitivity(1, true); + ointent->setItemSensitivity(2, true); + ointent->setItemSensitivity(3, true); + ointent->set_sensitive (false); + ointent->setSelected (1); + } +} + void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) { @@ -455,6 +487,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) disableListener (); + obpcconn.block (true); ipc.block (true); gamcsconn.block (true); tcurveconn.block(true); @@ -469,36 +502,50 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) if (pp->icm.input == "(none)") { inone->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, ""); } else if (pp->icm.input == "(embedded)" || ((pp->icm.input == "(camera)" || pp->icm.input == "") && icamera->get_state() == Gtk::STATE_INSENSITIVE)) { iembedded->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, ""); } else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state() != Gtk::STATE_INSENSITIVE) { icameraICC->set_active (true); - ckbBlendCMSMatrix->set_sensitive (true); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (true); + } updateDCP(pp->icm.dcpIlluminant, "(cameraICC)"); } else if ((pp->icm.input == "(cameraICC)") && icamera->get_state() != Gtk::STATE_INSENSITIVE && icameraICC->get_state() == Gtk::STATE_INSENSITIVE) { // this is the case when (cameraICC) is instructed by packaged profiles, but ICC file is not found // therefore falling back UI to explicitly reflect the (camera) option icamera->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, ""); } else if ((pp->icm.input == "(cameraICC)") && icamera->get_state() == Gtk::STATE_INSENSITIVE && icameraICC->get_state() == Gtk::STATE_INSENSITIVE) { // If neither (camera) nor (cameraICC) are available, as is the case when loading a non-raw, activate (embedded). iembedded->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, "(cameraICC)"); } else if ((pp->icm.input == "(camera)" || pp->icm.input == "") && icamera->get_state() != Gtk::STATE_INSENSITIVE) { icamera->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, ""); } else { ifromfile->set_active (true); oldip = pp->icm.input.substr(5); // cut of "file:" ipDialog->set_filename (pp->icm.input.substr(5)); - ckbBlendCMSMatrix->set_sensitive (true); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (true); + } updateDCP(pp->icm.dcpIlluminant, pp->icm.input.substr(5)); } @@ -514,8 +561,9 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) if (onames->get_active_row_number() == -1) { onames->set_active_text (M("TP_ICM_NOICM")); } - ointent->set_active(pp->icm.outputIntent); + ointent->setSelected (pp->icm.outputIntent); + obpc->set_active (pp->icm.outputBPC); ckbToneCurve->set_active (pp->icm.toneCurve); lastToneCurve = pp->icm.toneCurve; ckbApplyLookTable->set_active (pp->icm.applyLookTable); @@ -528,22 +576,29 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) ckbBlendCMSMatrix->set_active (pp->icm.blendCMSMatrix); lastBlendCMSMatrix = pp->icm.blendCMSMatrix; - onames->set_sensitive(wgamma->get_active_row_number() == 0 || freegamma->get_active()); //"default" - wgamma->set_sensitive(!freegamma->get_active()); - freegamma->set_active (pp->icm.freegamma); lastgamfree = pp->icm.freegamma; + if (!batchMode) { + onames->set_sensitive(wgamma->get_active_row_number() == 0 && !pp->icm.freegamma); //"default" + wgamma->set_sensitive(!pp->icm.freegamma); + gampos->set_sensitive(pp->icm.freegamma); + slpos->set_sensitive(pp->icm.freegamma); + updateRenderingIntent(pp->icm.output); + } + gampos->setValue (pp->icm.gampos); slpos->setValue (pp->icm.slpos); if (pedited) { iunchanged->set_active (!pedited->icm.input); + obpc->set_inconsistent(!pedited->icm.outputBPC); ckbToneCurve->set_inconsistent(!pedited->icm.toneCurve); ckbApplyLookTable->set_inconsistent(!pedited->icm.applyLookTable); ckbApplyBaselineExposureOffset->set_inconsistent(!pedited->icm.applyBaselineExposureOffset); ckbApplyHueSatMap->set_inconsistent(!pedited->icm.applyHueSatMap); ckbBlendCMSMatrix->set_inconsistent(!pedited->icm.blendCMSMatrix); + freegamma->set_inconsistent (!pedited->icm.freegamma); if (!pedited->icm.working) { wnames->set_active_text(M("GENERAL_UNCHANGED")); @@ -554,7 +609,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) } if (!pedited->icm.outputIntent) { - ointent->set_active_text(M("GENERAL_UNCHANGED")); + ointent->setSelected (4); } if (!pedited->icm.dcpIlluminant) { @@ -578,6 +633,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) hsmconn.block(false); gamcsconn.block (false); ipc.block (false); + obpcconn.block (false); enableListener (); } @@ -617,7 +673,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pp->icm.output = onames->get_active_text(); } - int ointentVal = ointent->get_active_row_number(); + int ointentVal = ointent->getSelected (); if (ointentVal >= 0 && ointentVal < RI__COUNT) { pp->icm.outputIntent = static_cast(ointentVal); } else { @@ -655,12 +711,14 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pp->icm.blendCMSMatrix = ckbBlendCMSMatrix->get_active (); pp->icm.gampos = (double) gampos->getValue(); pp->icm.slpos = (double) slpos->getValue(); + pp->icm.outputBPC = obpc->get_active (); if (pedited) { pedited->icm.input = !iunchanged->get_active (); pedited->icm.working = wnames->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.output = onames->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->icm.outputIntent = ointent->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->icm.outputIntent = ointent->getSelected () < 4; + pedited->icm.outputBPC = !obpc->get_inconsistent (); pedited->icm.dcpIlluminant = dcpIll->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent (); pedited->icm.applyLookTable = !ckbApplyLookTable->get_inconsistent (); @@ -697,7 +755,7 @@ void ICMPanel::setAdjusterBehavior (bool gammaadd, bool slopeadd) void ICMPanel::adjusterChanged (Adjuster* a, double newval) { - if (listener && freegamma->get_active()) { + if (listener && (freegamma->get_active() || batchMode)) { Glib::ustring costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), newval); @@ -735,7 +793,7 @@ void ICMPanel::dcpIlluminantChanged() void ICMPanel::toneCurveChanged() { - if (batchMode) { + if (multiImage) { if (ckbToneCurve->get_inconsistent()) { ckbToneCurve->set_inconsistent (false); tcurveconn.block (true); @@ -749,13 +807,19 @@ void ICMPanel::toneCurveChanged() } if (listener) { - listener->panelChanged (EvDCPToneCurve, ckbToneCurve->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbToneCurve->get_inconsistent()) { + listener->panelChanged (EvDCPToneCurve, M("GENERAL_UNCHANGED")); + } else if (ckbToneCurve->get_active()) { + listener->panelChanged (EvDCPToneCurve, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDCPToneCurve, M("GENERAL_DISABLED")); + } } } void ICMPanel::applyLookTableChanged() { - if (batchMode) { + if (multiImage) { if (ckbApplyLookTable->get_inconsistent()) { ckbApplyLookTable->set_inconsistent (false); ltableconn.block (true); @@ -769,13 +833,19 @@ void ICMPanel::applyLookTableChanged() } if (listener) { - listener->panelChanged (EvDCPApplyLookTable, ckbApplyLookTable->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbApplyLookTable->get_inconsistent()) { + listener->panelChanged (EvDCPApplyLookTable, M("GENERAL_UNCHANGED")); + } else if (ckbApplyLookTable->get_active()) { + listener->panelChanged (EvDCPApplyLookTable, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDCPApplyLookTable, M("GENERAL_DISABLED")); + } } } void ICMPanel::applyBaselineExposureOffsetChanged() { - if (batchMode) { + if (multiImage) { if (ckbApplyBaselineExposureOffset->get_inconsistent()) { ckbApplyBaselineExposureOffset->set_inconsistent (false); beoconn.block (true); @@ -789,13 +859,19 @@ void ICMPanel::applyBaselineExposureOffsetChanged() } if (listener) { - listener->panelChanged (EvDCPApplyBaselineExposureOffset, ckbApplyBaselineExposureOffset->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbApplyBaselineExposureOffset->get_inconsistent()) { + listener->panelChanged (EvDCPApplyBaselineExposureOffset, M("GENERAL_UNCHANGED")); + } else if (ckbApplyBaselineExposureOffset->get_active()) { + listener->panelChanged (EvDCPApplyBaselineExposureOffset, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDCPApplyBaselineExposureOffset, M("GENERAL_DISABLED")); + } } } void ICMPanel::applyHueSatMapChanged() { - if (batchMode) { + if (multiImage) { if (ckbApplyHueSatMap->get_inconsistent()) { ckbApplyHueSatMap->set_inconsistent (false); hsmconn.block (true); @@ -809,7 +885,13 @@ void ICMPanel::applyHueSatMapChanged() } if (listener) { - listener->panelChanged (EvDCPApplyHueSatMap, ckbApplyHueSatMap->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbApplyHueSatMap->get_inconsistent()) { + listener->panelChanged (EvDCPApplyHueSatMap, M("GENERAL_UNCHANGED")); + } else if (ckbApplyHueSatMap->get_active()) { + listener->panelChanged (EvDCPApplyHueSatMap, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDCPApplyHueSatMap, M("GENERAL_DISABLED")); + } } } @@ -846,7 +928,7 @@ void ICMPanel::ipChanged () void ICMPanel::blendCMSMatrixChanged() { - if (batchMode) { + if (multiImage) { if (ckbBlendCMSMatrix->get_inconsistent()) { ckbBlendCMSMatrix->set_inconsistent (false); blendcmsconn.block (true); @@ -860,13 +942,19 @@ void ICMPanel::blendCMSMatrixChanged() } if (listener) { - listener->panelChanged (EvBlendCMSMatrix, ckbBlendCMSMatrix->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbBlendCMSMatrix->get_inconsistent()) { + listener->panelChanged (EvBlendCMSMatrix, M("GENERAL_UNCHANGED")); + } else if (ckbBlendCMSMatrix->get_active()) { + listener->panelChanged (EvBlendCMSMatrix, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvBlendCMSMatrix, M("GENERAL_DISABLED")); + } } } void ICMPanel::GamChanged() { - if (batchMode) { + if (multiImage) { if (freegamma->get_inconsistent()) { freegamma->set_inconsistent (false); gamcsconn.block (true); @@ -880,31 +968,90 @@ void ICMPanel::GamChanged() } if (listener) { - if (freegamma->get_active()) { + if (freegamma->get_inconsistent()) { + listener->panelChanged (EvGAMFREE, M("GENERAL_UNCHANGED")); + } + else if (freegamma->get_active()) { listener->panelChanged (EvGAMFREE, M("GENERAL_ENABLED")); - onames->set_sensitive(!freegamma->get_active());//disabled choice - wgamma->set_sensitive(!freegamma->get_active()); + if (!batchMode) { + onames->set_sensitive(false);//disabled choice + wgamma->set_sensitive(false); + gampos->set_sensitive(true); + slpos->set_sensitive(true); + } } else { listener->panelChanged (EvGAMFREE, M("GENERAL_DISABLED")); - onames->set_sensitive(!freegamma->get_active() && wgamma->get_active_row_number() == 0); - wgamma->set_sensitive(!freegamma->get_active()); + if (!batchMode) { + onames->set_sensitive(wgamma->get_active_row_number() == 0); + wgamma->set_sensitive(true); + gampos->set_sensitive(false); + slpos->set_sensitive(false); + } } } } void ICMPanel::opChanged () { + if (!batchMode) { + updateRenderingIntent(onames->get_active_text()); + } if (listener) { listener->panelChanged (EvOProfile, onames->get_active_text()); } } -void ICMPanel::oiChanged () +void ICMPanel::oiChanged (int n) { if (listener) { - listener->panelChanged (EvOIntent, ointent->get_active_text()); + Glib::ustring str; + switch (n) { + case 0: + str = M("PREFERENCES_INTENT_PERCEPTUAL"); + break; + case 1: + str = M("PREFERENCES_INTENT_RELATIVE"); + break; + case 2: + str = M("PREFERENCES_INTENT_SATURATION"); + break; + case 3: + str = M("PREFERENCES_INTENT_ABSOLUTE"); + break; + case 4: + default: + str = M("GENERAL_UNCHANGED"); + break; + } + listener->panelChanged (EvOIntent, str); + } +} + +void ICMPanel::oBPCChanged () +{ + if (multiImage) { + if (obpc->get_inconsistent()) { + obpc->set_inconsistent (false); + obpcconn.block (true); + obpc->set_active (false); + obpcconn.block (false); + } else if (lastobpc) { + obpc->set_inconsistent (true); + } + + lastobpc = obpc->get_active (); + } + + if (listener) { + if (obpc->get_inconsistent()) { + listener->panelChanged (EvOBPCompens, M("GENERAL_UNCHANGED")); + } else if (obpc->get_active()) { + listener->panelChanged (EvOBPCompens, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvOBPCompens, M("GENERAL_DISABLED")); + } } } @@ -1006,7 +1153,8 @@ void ICMPanel::setBatchMode (bool batchMode) iVBox->reorder_child (*iunchanged, 5); removeIfThere (this, saveRef); onames->append_text (M("GENERAL_UNCHANGED")); - ointent->append_text (M("GENERAL_UNCHANGED")); + ointent->addEntry("unchanged-22.png", M("GENERAL_UNCHANGED")); + ointent->show(); wnames->append_text (M("GENERAL_UNCHANGED")); wgamma->append_text (M("GENERAL_UNCHANGED")); dcpIll->append_text (M("GENERAL_UNCHANGED")); diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 538e3f79c..caab1771f 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -25,6 +25,7 @@ #include "guiutils.h" #include "toolpanel.h" +#include "popupbutton.h" #include "../rtengine/imagedata.h" class ICMPanelListener @@ -53,6 +54,8 @@ protected: sigc::connection beoconn; bool lastApplyHueSatMap; sigc::connection hsmconn; + bool lastobpc; + sigc::connection obpcconn; bool lastBlendCMSMatrix; bool isBatchMode; sigc::connection blendcmsconn; @@ -60,6 +63,7 @@ protected: private: Gtk::VBox * iVBox; + Gtk::CheckButton* obpc; Gtk::CheckButton* freegamma; Gtk::RadioButton* inone; @@ -78,7 +82,7 @@ private: MyComboBoxText* wgamma; MyComboBoxText* onames; - MyComboBoxText* ointent; + PopUpButton* ointent; Gtk::RadioButton* ofromdir; Gtk::RadioButton* ofromfile; Gtk::RadioButton* iunchanged; @@ -95,6 +99,7 @@ private: Glib::ustring lastRefFilename; Glib::ustring camName; void updateDCP(int dcpIlluminant, Glib::ustring dcp_name); + void updateRenderingIntent (const Glib::ustring &profile); public: ICMPanel (); @@ -107,7 +112,8 @@ public: void wpChanged (); void opChanged (); - void oiChanged (); + void oiChanged (int n); + void oBPCChanged (); void ipChanged (); void gpChanged (); void GamChanged (); diff --git a/rtgui/options.cc b/rtgui/options.cc index a46ec9f90..1b01a66db 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -390,8 +390,8 @@ void Options::setDefaults () gimpDir = ""; psDir = ""; customEditorProg = ""; + CPBKeys = CPBKT_TID; editorToSendTo = 1; - liveThumbnails = true; favoriteDirs.clear(); tpOpen.clear (); //crvOpen.clear (); @@ -468,6 +468,7 @@ void Options::setDefaults () fastexport_icm_working = "ProPhoto"; fastexport_icm_output = "RT_sRGB"; fastexport_icm_outputIntent = rtengine::RI_RELATIVE; + fastexport_icm_outputBPC = true; fastexport_icm_gamma = "default"; fastexport_resize_enabled = true; fastexport_resize_scale = 1; @@ -633,6 +634,7 @@ void Options::setDefaults () rtSettings.monitorProfile = Glib::ustring(); rtSettings.monitorIntent = rtengine::RI_RELATIVE; + rtSettings.monitorBPC = true; rtSettings.autoMonitorProfile = false; rtSettings.adobe = "RT_Medium_gsRGB"; // put the name of yours profiles (here windows) rtSettings.prophoto = "RT_Large_gBT709"; // these names appear in the menu "output profile" @@ -1087,10 +1089,6 @@ int Options::readFromFile (Glib::ustring fname) thumbInterp = keyFile.get_integer ("File Browser", "ThumbnailInterpolation"); } - if (keyFile.has_key ("File Browser", "LiveThumbnails")) { - liveThumbnails = keyFile.get_boolean ("File Browser", "LiveThumbnails"); - } - if (keyFile.has_key ("File Browser", "FavoriteDirs")) { favoriteDirs = keyFile.get_string_list ("File Browser", "FavoriteDirs"); } @@ -1472,6 +1470,10 @@ int Options::readFromFile (Glib::ustring fname) rtSettings.monitorIntent = static_cast(keyFile.get_integer("Color Management", "Intent")); } + if (keyFile.has_key ("Color Management", "MonitorBPC")) { + rtSettings.monitorBPC = keyFile.get_boolean("Color Management", "MonitorBPC"); + } + if (keyFile.has_key ("Color Management", "CRI")) { rtSettings.CRI_color = keyFile.get_integer("Color Management", "CRI"); } @@ -1728,6 +1730,10 @@ int Options::readFromFile (Glib::ustring fname) fastexport_icm_outputIntent = static_cast(keyFile.get_integer ("Fast Export", "fastexport_icm_output_intent" )); } + if (keyFile.has_key ("Fast Export", "fastexport_icm_output_bpc" )) { + fastexport_icm_outputBPC = keyFile.get_boolean ("Fast Export", "fastexport_icm_output_bpc" ); + } + if (keyFile.has_key ("Fast Export", "fastexport_icm_gamma" )) { fastexport_icm_gamma = keyFile.get_string ("Fast Export", "fastexport_icm_gamma" ); } @@ -1787,13 +1793,9 @@ int Options::readFromFile (Glib::ustring fname) } } catch (Glib::Error &err) { - if (options.rtSettings.verbose) { - printf("Options::readFromFile / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); - } + printf("Options::readFromFile / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); } catch (...) { - if (options.rtSettings.verbose) { - printf("Options::readFromFile / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); - } + printf("Options::readFromFile / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); } return 1; @@ -1884,7 +1886,6 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_integer_list ("File Browser", "ParseExtensionsEnabled", pextena); keyFile.set_integer ("File Browser", "ThumbnailArrangement", fbArrangement); keyFile.set_integer ("File Browser", "ThumbnailInterpolation", thumbInterp); - keyFile.set_boolean ("File Browser", "LiveThumbnails", liveThumbnails); Glib::ArrayHandle pfav = favoriteDirs; keyFile.set_string_list ("File Browser", "FavoriteDirs", pfav); Glib::ArrayHandle pren = renameTemplates; @@ -2036,6 +2037,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_boolean ("Color Management", "Autocielab", rtSettings.autocielab); keyFile.set_boolean ("Color Management", "RGBcurvesLumamode_Gamut", rtSettings.rgbcurveslumamode_gamut); keyFile.set_integer ("Color Management", "Intent", rtSettings.monitorIntent); + keyFile.set_boolean ("Color Management", "MonitorBPC", rtSettings.monitorBPC); keyFile.set_integer ("Color Management", "view", rtSettings.viewingdevice); keyFile.set_integer ("Color Management", "grey", rtSettings.viewingdevicegrey); keyFile.set_integer ("Color Management", "greySc", rtSettings.viewinggreySc); @@ -2104,6 +2106,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_string ("Fast Export", "fastexport_icm_working" , fastexport_icm_working ); keyFile.set_string ("Fast Export", "fastexport_icm_output" , fastexport_icm_output ); keyFile.set_integer ("Fast Export", "fastexport_icm_output_intent" , fastexport_icm_outputIntent ); + keyFile.set_boolean ("Fast Export", "fastexport_icm_output_bpc" , fastexport_icm_outputBPC ); keyFile.set_string ("Fast Export", "fastexport_icm_gamma" , fastexport_icm_gamma ); keyFile.set_boolean ("Fast Export", "fastexport_resize_enabled" , fastexport_resize_enabled ); keyFile.set_double ("Fast Export", "fastexport_resize_scale" , fastexport_resize_scale ); diff --git a/rtgui/options.h b/rtgui/options.h index b0cb7b987..ab0726798 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -180,9 +180,7 @@ public: int editorToSendTo; int maxThumbnailHeight; std::size_t maxCacheEntries; - ThFileType thumbnailFormat; int thumbInterp; // 0: nearest, 1: bilinear - bool liveThumbnails; std::vector parseExtensions; // List containing all extensions type std::vector parseExtensionsEnabled; // List of bool to retain extension or not std::vector parsedExtensions; // List containing all retained extensions (lowercase) @@ -203,7 +201,6 @@ public: bool showFileNames; bool filmStripShowFileNames; bool tabbedUI; - int previewSizeTab, previewSizeBrowser; bool rememberZoomAndPan; int multiDisplayMode; // 0=none, 1=Edit panels on other display std::vector cutOverlayBrush; // Red;Green;Blue;Alpha , all ranging 0..1 @@ -219,7 +216,6 @@ public: //int histogramWorking; // 0=disabled, 1=left pane, 2=right pane bool histogramBar; bool histogramFullMode; - bool showProfileSelector; bool FileBrowserToolbarSingleRow; bool hideTPVScrollbar; bool UseIconNoText; @@ -270,6 +266,7 @@ public: Glib::ustring fastexport_icm_working; Glib::ustring fastexport_icm_output; rtengine::RenderingIntent fastexport_icm_outputIntent; + bool fastexport_icm_outputBPC; Glib::ustring fastexport_icm_gamma; bool fastexport_resize_enabled; double fastexport_resize_scale; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 0422f7403..ff3e4c0b1 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -353,8 +353,9 @@ void ParamsEdited::set (bool v) icm.working = v; icm.output = v; icm.outputIntent = v; + icm.outputBPC = v; icm.gamma = v; - icm.freegamma = v; + icm.freegamma = v; icm.gampos = v; icm.slpos = v; raw.bayersensor.method = v; @@ -847,6 +848,7 @@ void ParamsEdited::initFrom (const std::vector icm.working = icm.working && p.icm.working == other.icm.working; icm.output = icm.output && p.icm.output == other.icm.output; icm.outputIntent = icm.outputIntent && p.icm.outputIntent == other.icm.outputIntent; + icm.outputBPC = icm.outputBPC && p.icm.outputBPC == other.icm.outputBPC ; icm.gamma = icm.gamma && p.icm.gamma == other.icm.gamma; icm.freegamma = icm.freegamma && p.icm.freegamma == other.icm.freegamma; icm.gampos = icm.gampos && p.icm.gampos == other.icm.gampos; @@ -2210,8 +2212,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.icm.outputIntent = mods.icm.outputIntent; } - //if (icm.gampos) toEdit.icm.gampos = mods.icm.gampos; - //if (icm.slpos) toEdit.icm.slpos = mods.icm.slpos; + if (icm.outputBPC) { + toEdit.icm.outputBPC = mods.icm.outputBPC; + } + if (icm.gampos) { toEdit.icm.gampos = dontforceSet && options.baBehav[ADDSET_FREE_OUPUT_GAMMA] ? toEdit.icm.gampos + mods.icm.gampos : mods.icm.gampos; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 503d6ee29..19d143398 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -544,6 +544,7 @@ public: bool working; bool output; bool outputIntent; + bool outputBPC; bool gamma; bool gampos; bool slpos; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 0858066fa..4364894de 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -699,15 +699,19 @@ Gtk::Widget* Preferences::getColorManagementPanel () monProfile->append_text (M("PREFERENCES_PROFILE_NONE")); monProfile->set_active (0); - const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (); + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (true); for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) monProfile->append_text (*profile); - monIntent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + // same order as the enum monIntent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + monIntent->append_text (M("PREFERENCES_INTENT_RELATIVE")); monIntent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); monIntent->set_active (1); + monBPC = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_MONBPC"))); + monBPC->set_active (true); + iccDir->signal_selection_changed ().connect (sigc::mem_fun (this, &Preferences::iccDirChanged)); #if defined(WIN32) // Auto-detection not implemented for Linux, see issue 851 @@ -717,22 +721,24 @@ Gtk::Widget* Preferences::getColorManagementPanel () Gtk::Table* colt = Gtk::manage (new Gtk::Table (3, 2)); int row = 0; - colt->attach (*pdlabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*iccDir, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*pdlabel, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*iccDir, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); #if !defined(__APPLE__) // monitor profile not supported on apple ++row; - colt->attach (*mplabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*monProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*mplabel, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*monProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); #if defined(WIN32) ++row; - colt->attach (*cbAutoMonProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*cbAutoMonProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); #endif #endif ++row; - colt->attach (*milabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*monIntent, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*milabel, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*monIntent, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); mvbcm->pack_start (*colt, Gtk::PACK_SHRINK, 4); + mvbcm->pack_start (*monBPC, Gtk::PACK_SHRINK, 4); + #if defined(WIN32) autoMonProfileToggled(); #endif @@ -1458,15 +1464,16 @@ void Preferences::storePreferences () switch (monIntent->get_active_row_number ()) { default: case 0: - moptions.rtSettings.monitorIntent = rtengine::RI_RELATIVE; + moptions.rtSettings.monitorIntent = rtengine::RI_PERCEPTUAL; break; case 1: - moptions.rtSettings.monitorIntent = rtengine::RI_PERCEPTUAL; + moptions.rtSettings.monitorIntent = rtengine::RI_RELATIVE; break; case 2: moptions.rtSettings.monitorIntent = rtengine::RI_ABSOLUTE; break; } + moptions.rtSettings.monitorBPC = monBPC->get_active (); #if defined(WIN32) moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active (); #endif @@ -1587,16 +1594,17 @@ void Preferences::fillPreferences () setActiveTextOrIndex (*monProfile, moptions.rtSettings.monitorProfile, 0); switch (moptions.rtSettings.monitorIntent) { default: - case rtengine::RI_RELATIVE: + case rtengine::RI_PERCEPTUAL: monIntent->set_active (0); break; - case rtengine::RI_PERCEPTUAL: + case rtengine::RI_RELATIVE: monIntent->set_active (1); break; case rtengine::RI_ABSOLUTE: monIntent->set_active (2); break; } + monBPC->set_active (moptions.rtSettings.monitorBPC); #if defined(WIN32) cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); #endif diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 6da1a9669..a94601663 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -97,6 +97,7 @@ protected: Gtk::FileChooserButton* iccDir; Gtk::ComboBoxText* monProfile; Gtk::ComboBoxText* monIntent; + Gtk::CheckButton* monBPC; Gtk::CheckButton* cbAutoMonProfile; //Gtk::CheckButton* cbAutocielab; Gtk::CheckButton* cbciecamfloat; diff --git a/rtgui/rawprocess.cc b/rtgui/rawprocess.cc deleted file mode 100644 index 0ca4350cc..000000000 --- a/rtgui/rawprocess.cc +++ /dev/null @@ -1,303 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 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 "rawprocess.h" -#include "options.h" -#include "guiutils.h" -using namespace rtengine; -using namespace rtengine::procparams; - -RawProcess::RawProcess () : FoldableToolPanel(this) -{ - Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); - hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") + ": ")), Gtk::PACK_SHRINK, 4); - dmethod = Gtk::manage (new MyComboBoxText ()); - - for( size_t i = 0; i < procparams::RAWParams::numMethods; i++) { - dmethod->append_text(procparams::RAWParams::methodstring[i]); - } - - dmethod->set_active(0); - hb1->set_tooltip_markup (M("TP_RAW_DMETHOD_TOOLTIP")); - - hb1->pack_end (*dmethod, Gtk::PACK_EXPAND_WIDGET, 4); - pack_start( *hb1, Gtk::PACK_SHRINK, 4); - - dcbOptions = Gtk::manage (new Gtk::VBox ()); - dcbOptions->set_border_width(4); - - dcbIterations = Gtk::manage (new Adjuster (M("TP_RAW_DCBITERATIONS"), 0, 5, 1, 2)); - dcbIterations->setAdjusterListener (this); - - if (dcbIterations->delay < options.adjusterMaxDelay) { - dcbIterations->delay = options.adjusterMaxDelay; - } - - dcbIterations->show(); - dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_DCBENHANCE"))); - dcbOptions->pack_start(*dcbIterations); - dcbOptions->pack_start(*dcbEnhance); - pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); - - lmmseOptions = Gtk::manage (new Gtk::VBox ()); - lmmseOptions->set_border_width(4); - - lmmseIterations = Gtk::manage (new Adjuster (M("TP_RAW_LMMSEITERATIONS"), 0, 6, 1, 2)); - lmmseIterations->setAdjusterListener (this); - lmmseIterations->set_tooltip_markup (M("TP_RAW_LMMSE_TOOLTIP")); - - if (lmmseIterations->delay < options.adjusterMaxDelay) { - lmmseIterations->delay = options.adjusterMaxDelay; - } - - lmmseIterations->show(); - lmmseOptions->pack_start(*lmmseIterations); - pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4); - - pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 )); - ccSteps->setAdjusterListener (this); - - if (ccSteps->delay < options.adjusterMaxDelay) { - ccSteps->delay = options.adjusterMaxDelay; - } - - ccSteps->show(); - pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); - - //pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - //allOptions = Gtk::manage (new Gtk::VBox ()); - //allOptions->set_border_width(2); - //allEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_ALLENHANCE"))); - //allOptions->pack_start(*allEnhance); - //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); - - methodconn = dmethod->signal_changed().connect( sigc::mem_fun(*this, &RawProcess::methodChanged) ); - dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::dcbEnhanceChanged), true); - //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::allEnhanceChanged), true); -} - - -void RawProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - methodconn.block (true); - dcbEnhconn.block (true); - //allEnhconn.block (true); - - dmethod->set_active(procparams::RAWParams::numMethods); - - for( size_t i = 0; i < procparams::RAWParams::numMethods; i++) - if( pp->raw.dmethod == procparams::RAWParams::methodstring[i]) { - dmethod->set_active(i); - oldSelection = i; - break; - } - - if(pedited ) { - ccSteps->setEditedState (pedited->raw.ccSteps ? Edited : UnEdited); - dcbIterations->setEditedState ( pedited->raw.dcbIterations ? Edited : UnEdited); - dcbEnhance->set_inconsistent(!pedited->raw.dcbEnhance); - //allEnhance->set_inconsistent(!pedited->raw.allEnhance); - lmmseIterations->setEditedState ( pedited->raw.lmmseIterations ? Edited : UnEdited); - - if( !pedited->raw.dmethod ) { - dmethod->set_active(procparams::RAWParams::numMethods); // No name - } - } - - //allEnhance->set_active(pp->raw.all_enhance); - - dcbIterations->setValue (pp->raw.dcb_iterations); - dcbEnhance->set_active(pp->raw.dcb_enhance); - ccSteps->setValue (pp->raw.ccSteps); - - if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::dcb] || - dmethod->get_active_row_number() == procparams::RAWParams::numMethods) { - dcbOptions->show(); - } else { - dcbOptions->hide(); - } - - lmmseIterations->setValue (pp->raw.lmmse_iterations); - - if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::lmmse] || - dmethod->get_active_row_number() == procparams::RAWParams::numMethods) { - lmmseOptions->show(); - } else { - lmmseOptions->hide(); - } - - // Flase color suppression is applied to all demozaicing method, so don't hide anything - /*if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::eahd] || - pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::hphd] || - pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::vng4]) - ccSteps->show(); - else - ccSteps->hide();*/ - - lastDCBen = pp->raw.dcb_enhance; - //lastALLen = pp->raw.all_enhance; - - methodconn.block (false); - dcbEnhconn.block (false); - //allEnhconn.block (false); - - enableListener (); -} - -void RawProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.ccSteps = ccSteps->getIntValue(); - pp->raw.dcb_iterations = dcbIterations->getIntValue(); - pp->raw.dcb_enhance = dcbEnhance->get_active(); - //pp->raw.all_enhance = allEnhance->get_active(); - pp->raw.lmmse_iterations = lmmseIterations->getIntValue(); - - int currentRow = dmethod->get_active_row_number(); - - if( currentRow >= 0 && currentRow < procparams::RAWParams::numMethods) { - pp->raw.dmethod = procparams::RAWParams::methodstring[currentRow]; - } - - if (pedited) { - pedited->raw.ccSteps = ccSteps->getEditedState (); - pedited->raw.dmethod = dmethod->get_active_row_number() != procparams::RAWParams::numMethods; - pedited->raw.dcbIterations = dcbIterations->getEditedState (); - pedited->raw.dcbEnhance = !dcbEnhance->get_inconsistent(); - //pedited->raw.allEnhance = !allEnhance->get_inconsistent(); - pedited->raw.lmmseIterations = lmmseIterations->getEditedState (); - - } -} - -void RawProcess::setBatchMode(bool batchMode) -{ - dmethod->append_text (M("GENERAL_UNCHANGED")); - dmethod->set_active(procparams::RAWParams::numMethods); // No name - dcbOptions->hide(); - lmmseOptions->hide(); - ToolPanel::setBatchMode (batchMode); - ccSteps->showEditedCB (); - dcbIterations->showEditedCB (); - lmmseIterations->showEditedCB (); - -} - -void RawProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - dcbIterations->setDefault( defParams->raw.dcb_iterations); - lmmseIterations->setDefault( defParams->raw.lmmse_iterations); - ccSteps->setDefault (defParams->raw.ccSteps); - - if (pedited) { - dcbIterations->setDefaultEditedState( pedited->raw.dcbIterations ? Edited : UnEdited); - lmmseIterations->setDefaultEditedState( pedited->raw.lmmseIterations ? Edited : UnEdited); - ccSteps->setDefaultEditedState(pedited->raw.ccSteps ? Edited : UnEdited); - } else { - dcbIterations->setDefaultEditedState( Irrelevant ); - lmmseIterations->setDefaultEditedState( Irrelevant ); - ccSteps->setDefaultEditedState(Irrelevant ); - } -} - -void RawProcess::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - if (a == dcbIterations) { - listener->panelChanged (EvDemosaicDCBIter, a->getTextValue() ); - } else if (a == ccSteps) { - listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); - } else if (a == lmmseIterations) { - listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); - } - - } -} - -void RawProcess::methodChanged () -{ - int curSelection = dmethod->get_active_row_number(); - - if ( curSelection == procparams::RAWParams::dcb) { - dcbOptions->show(); - } else { - dcbOptions->hide(); - } - - if ( curSelection == procparams::RAWParams::lmmse) { - lmmseOptions->show(); - } else { - lmmseOptions->hide(); - } - - Glib::ustring methodName = ""; - bool ppreq = false; - - if( curSelection >= 0 && curSelection < procparams::RAWParams::numMethods) { - methodName = procparams::RAWParams::methodstring[curSelection]; - - if (curSelection == procparams::RAWParams::mono || oldSelection == procparams::RAWParams::mono) { - ppreq = true; - } - } - - oldSelection = curSelection; - - if (listener) { - listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); - } -} - -void RawProcess::dcbEnhanceChanged () -{ - if (batchMode) { - if (dcbEnhance->get_inconsistent()) { - dcbEnhance->set_inconsistent (false); - dcbEnhconn.block (true); - dcbEnhance->set_active (false); - dcbEnhconn.block (false); - } else if (lastDCBen) { - dcbEnhance->set_inconsistent (true); - } - - lastDCBen = dcbEnhance->get_active (); - } - - if (listener) { - listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - -/*void RawProcess::allEnhanceChanged () -{ - if (batchMode) { - if (allEnhance->get_inconsistent()) { - allEnhance->set_inconsistent (false); - allEnhconn.block (true); - allEnhance->set_active (false); - allEnhconn.block (false); - } - else if (lastALLen) - allEnhance->set_inconsistent (true); - - lastALLen = allEnhance->get_active (); - } - if (listener) - listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -}*/ diff --git a/rtgui/rawprocess.h b/rtgui/rawprocess.h deleted file mode 100644 index 85c1c9f44..000000000 --- a/rtgui/rawprocess.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 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 . - */ -#ifndef _RAWPROCESS_H_ -#define _RAWPROCESS_H_ - -#include -#include "adjuster.h" -#include "guiutils.h" -#include "toolpanel.h" - - -class RawProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel -{ - -protected: - - MyComboBoxText* dmethod; - Gtk::Label* methodl; - Adjuster* ccSteps; - Gtk::VBox *dcbOptions; - Adjuster* dcbIterations; - Gtk::CheckButton* dcbEnhance; - //Gtk::VBox *allOptions; - //Gtk::CheckButton* allEnhance; - Gtk::VBox *lmmseOptions; - Adjuster* lmmseIterations; - - bool lastDCBen; - int oldSelection; - //bool lastALLen; - sigc::connection methodconn, dcbEnhconn; //,allEnhconn; -public: - - RawProcess (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = NULL); - - void methodChanged (); - void adjusterChanged (Adjuster* a, double newval); - void dcbEnhanceChanged(); - //void allEnhanceChanged(); - -}; - -#endif diff --git a/rtgui/thumbbrowserentry.cc b/rtgui/thumbbrowserentry.cc deleted file mode 100644 index 1c491a641..000000000 --- a/rtgui/thumbbrowserentry.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 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 - -FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) - : ThumbBrowserEntryBase (fname), thumbnail(thm) -{ - - previewOwner = false; - italicstyle = thumbnail->getType() != FT_Raw; - datetimeline = thumbnail->getDateTimeString (); - exifline = thumbnail->getExifString (); -} - -void ThumbBrowserEntry::obtainThumbnailSize () -{ - - if (thumbnail) { - thumbnail->getThumbnailSize (prew, preh); - } -} -Glib::RefPtr ThumbBrowserEntry::editedIcon; -Glib::RefPtr ThumbBrowserEntry::recentlySavedIcon; -Glib::RefPtr ThumbBrowserEntry::enqueuedIcon; -std::vector > ThumbBrowserEntry::getIconsOnImageArea () -{ - - std::vector > ret; - - if (!thumbnail) { - return ret; - } - - if (thumbnail->hasProcParams() && editedIcon) { - ret.push_back (editedIcon); - } - - if (thumbnail->isRecentlySaved() && recentlySavedIcon) { - ret.push_back (recentlySavedIcon); - } - - if (thumbnail->isEnqueued () && enqueuedIcon) { - ret.push_back (enqueuedIcon); - } - - return ret; -} - -ThumbnailButtonSet* ThumbBrowserEntry::getThumbButtonSet () -{ - - return (ThumbnailButtonSet*)buttonSet; -} diff --git a/tools/color_management.svg b/tools/color_management.svg new file mode 100644 index 000000000..d60fcefd3 --- /dev/null +++ b/tools/color_management.svg @@ -0,0 +1,655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + Output ICC profile & intent + + + Monitor ICC profile & intent + + + Monitor + + + + Printer + + + + Output file + + + Soft-proofing path(Output Black Point Compensation) + Only ifoptions.rtSettings.HistogramWorking = 1(Output Black Point Compensation) + + + L*a*b image + End of pipeline + + Normal path(Monitor Black Point Compensation) + + Used fo image analysis only withoptions.rtSettings.HistogramWorking = 1 + Used fo image analysis withoptions.rtSettings.HistogramWorking = 0 + + Working space profile (output intent) + "Working" image + Output image * + Preview image + + * When options.rtSettings.HistogramWorking = 1 and soft-proofing is enabled, the Output image does not really exist, i.e. no memory is allocated, the CMM only makes a double conversion of each pixel of the Lab image + + diff --git a/tools/source_icons/scalable/spGamutCheck.file b/tools/source_icons/scalable/spGamutCheck.file new file mode 100644 index 000000000..f8b0d6338 --- /dev/null +++ b/tools/source_icons/scalable/spGamutCheck.file @@ -0,0 +1 @@ +spGamutCheck.png,w22,actions diff --git a/tools/source_icons/scalable/spGamutCheck.svg b/tools/source_icons/scalable/spGamutCheck.svg new file mode 100644 index 000000000..9748e3916 --- /dev/null +++ b/tools/source_icons/scalable/spGamutCheck.svg @@ -0,0 +1,1344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + ! + diff --git a/tools/source_icons/scalable/unchanged.file b/tools/source_icons/scalable/unchanged.file new file mode 100644 index 000000000..bfeb052cd --- /dev/null +++ b/tools/source_icons/scalable/unchanged.file @@ -0,0 +1,2 @@ +unchanged-22.png,w22,actions +unchanged-18.png,w18,actions diff --git a/tools/source_icons/scalable/unchanged.svg b/tools/source_icons/scalable/unchanged.svg new file mode 100644 index 000000000..f0178a78a --- /dev/null +++ b/tools/source_icons/scalable/unchanged.svg @@ -0,0 +1,1357 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + +