From 8b44ed0fd81326f3b1a54f6063c03931f0013631 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 8 May 2017 18:42:13 +0200 Subject: [PATCH 01/32] Speedup for microcontrast, issue #3867 --- rtengine/ipsharpen.cc | 412 ++++++++++++++++-------------------------- rtengine/rt_math.h | 7 + 2 files changed, 166 insertions(+), 253 deletions(-) diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index 00196591e..7ef323f08 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -24,7 +24,8 @@ #include "sleef.c" #include "opthelper.h" using namespace std; - +#define BENCHMARK +#include "StopWatch.h" namespace rtengine { @@ -561,27 +562,21 @@ void ImProcFunctions::MLsharpen (LabImage* lab) //! MicroContrast is a sharpening method developed by Manuel Llorens and documented here: http://www.rawness.es/sharpening/?lang=en //!
The purpose is maximize clarity of the image without creating halo's. //!
Addition from JD : pyramid + pondered contrast with matrix 5x5 +//!
2017 Ingo Weyrich : reduced processing time //! \param luminance : Luminance channel of image void ImProcFunctions::MLmicrocontrast(float** luminance, int W, int H) { if (!params->sharpenMicro.enabled) { return; } +BENCHFUN - MyTime t1e, t2e; - t1e.set(); - - int k = params->sharpenMicro.matrix ? 1 : 2; + const int k = params->sharpenMicro.matrix ? 1 : 2; // k=2 matrix 5x5 k=1 matrix 3x3 - int offset, offset2, i, j, col, row, n; - float temp, temp2, temp3, temp4, tempL; - float *LM, v, s, contrast; - int signs[25]; - int width = W, height = H; - float uniform = params->sharpenMicro.uniformity;//between 0 to 100 - int unif; - unif = (int)(uniform / 10.0f); //put unif between 0 to 10 + const int width = W, height = H; + const float uniform = params->sharpenMicro.uniformity;//between 0 to 100 + const int unif = (int)(uniform / 10.0f); //put unif between 0 to 10 float amount = params->sharpenMicro.amount / 1500.0f; //amount 2000.0 quasi no artefacts ==> 1500 = maximum, after artefacts if (amount < 0.000001f) { @@ -594,127 +589,108 @@ void ImProcFunctions::MLmicrocontrast(float** luminance, int W, int H) if (settings->verbose) { printf ("Micro-contrast amount %f\n", amount); - } - - if (settings->verbose) { printf ("Micro-contrast uniformity %i\n", unif); } //modulation uniformity in function of luminance - float L98[11] = {0.001f, 0.0015f, 0.002f, 0.004f, 0.006f, 0.008f, 0.01f, 0.03f, 0.05f, 0.1f, 0.1f}; - float L95[11] = {0.0012f, 0.002f, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.12f, 0.15f, 0.2f, 0.25f}; - float L92[11] = {0.01f, 0.015f, 0.02f, 0.06f, 0.10f, 0.13f, 0.17f, 0.25f, 0.3f, 0.32f, 0.35f}; - float L90[11] = {0.015f, 0.02f, 0.04f, 0.08f, 0.12f, 0.15f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f}; - float L87[11] = {0.025f, 0.03f, 0.05f, 0.1f, 0.15f, 0.25f, 0.3f, 0.4f, 0.5f, 0.63f, 0.75f}; - float L83[11] = {0.055f, 0.08f, 0.1f, 0.15f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.75f, 0.85f}; - float L80[11] = {0.15f, 0.2f, 0.25f, 0.3f, 0.35f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f}; - float L75[11] = {0.22f, 0.25f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.85f, 0.9f, 0.95f}; - float L70[11] = {0.35f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.97f, 1.0f, 1.0f, 1.0f, 1.0f}; - float L63[11] = {0.55f, 0.6f, 0.7f, 0.8f, 0.85f, 0.9f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; - float L58[11] = {0.75f, 0.77f, 0.8f, 0.9f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; + const float L98[11] = {0.001f, 0.0015f, 0.002f, 0.004f, 0.006f, 0.008f, 0.01f, 0.03f, 0.05f, 0.1f, 0.1f}; + const float L95[11] = {0.0012f, 0.002f, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.12f, 0.15f, 0.2f, 0.25f}; + const float L92[11] = {0.01f, 0.015f, 0.02f, 0.06f, 0.10f, 0.13f, 0.17f, 0.25f, 0.3f, 0.32f, 0.35f}; + const float L90[11] = {0.015f, 0.02f, 0.04f, 0.08f, 0.12f, 0.15f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f}; + const float L87[11] = {0.025f, 0.03f, 0.05f, 0.1f, 0.15f, 0.25f, 0.3f, 0.4f, 0.5f, 0.63f, 0.75f}; + const float L83[11] = {0.055f, 0.08f, 0.1f, 0.15f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.75f, 0.85f}; + const float L80[11] = {0.15f, 0.2f, 0.25f, 0.3f, 0.35f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f}; + const float L75[11] = {0.22f, 0.25f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.85f, 0.9f, 0.95f}; + const float L70[11] = {0.35f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.97f, 1.0f, 1.0f, 1.0f, 1.0f}; + const float L63[11] = {0.55f, 0.6f, 0.7f, 0.8f, 0.85f, 0.9f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; + const float L58[11] = {0.75f, 0.77f, 0.8f, 0.9f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; //default 5 //modulation contrast - float Cont0[11] = {0.05f, 0.1f, 0.2f, 0.25f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f}; - float Cont1[11] = {0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 0.95f, 1.0f}; - float Cont2[11] = {0.2f, 0.40f, 0.6f, 0.7f, 0.8f, 0.85f, 0.90f, 0.95f, 1.0f, 1.05f, 1.10f}; - float Cont3[11] = {0.5f, 0.6f, 0.7f, 0.8f, 0.85f, 0.9f, 1.0f, 1.0f, 1.05f, 1.10f, 1.20f}; - float Cont4[11] = {0.8f, 0.85f, 0.9f, 0.95f, 1.0f, 1.05f, 1.10f, 1.150f, 1.2f, 1.25f, 1.40f}; - float Cont5[11] = {1.0f, 1.1f, 1.2f, 1.25f, 1.3f, 1.4f, 1.45f, 1.50f, 1.6f, 1.65f, 1.80f}; + const float Cont0[11] = {0.05f, 0.1f, 0.2f, 0.25f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f}; + const float Cont1[11] = {0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 0.95f, 1.0f}; + const float Cont2[11] = {0.2f, 0.40f, 0.6f, 0.7f, 0.8f, 0.85f, 0.90f, 0.95f, 1.0f, 1.05f, 1.10f}; + const float Cont3[11] = {0.5f, 0.6f, 0.7f, 0.8f, 0.85f, 0.9f, 1.0f, 1.0f, 1.05f, 1.10f, 1.20f}; + const float Cont4[11] = {0.8f, 0.85f, 0.9f, 0.95f, 1.0f, 1.05f, 1.10f, 1.150f, 1.2f, 1.25f, 1.40f}; + const float Cont5[11] = {1.0f, 1.1f, 1.2f, 1.25f, 1.3f, 1.4f, 1.45f, 1.50f, 1.6f, 1.65f, 1.80f}; + + const float s = amount; + const float sqrt2 = sqrt(2.0); + const float sqrt1d25 = sqrt(1.25); + float *LM = new float[width * height]; //allocation for Luminance - float chmax = 8.0f; - LM = new float[width * height]; //allocation for Luminance #ifdef _OPENMP - #pragma omp parallel for private(offset, i,j) shared(LM) + #pragma omp parallel +#endif +{ + float signs[25]; + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) #endif - for(j = 0; j < height; j++) - for(i = 0, offset = j * width + i; i < width; i++, offset++) { + for(int j = 0; j < height; j++) + for(int i = 0, offset = j * width + i; i < width; i++, offset++) { LM[offset] = luminance[j][i] / 327.68f; // adjust to 0.100 and to RT variables } #ifdef _OPENMP - #pragma omp parallel for private(j,i,offset,s,signs,v,n,row,col,offset2,contrast,temp,temp2,tempL,temp4) shared(luminance,LM,amount,chmax,unif,k,L98,L95,L92,L90,L87,L83,L80,L75,L70,L63,L58,Cont0,Cont1,Cont2,Cont3,Cont4,Cont5) + #pragma omp for schedule(dynamic,16) #endif - for(j = k; j < height - k; j++) - for(i = k, offset = j * width + i; i < width - k; i++, offset++) { - s = amount; - v = LM[offset]; - n = 0; - - for(row = j - k; row <= j + k; row++) - for(col = i - k, offset2 = row * width + col; col <= i + k; col++, offset2++) { - signs[n] = 0; - - if (v < LM[offset2]) { - signs[n] = -1; - } - - if (v > LM[offset2]) { - signs[n] = 1; - } + for(int j = k; j < height - k; j++) + for(int i = k, offset = j * width + i; i < width - k; i++, offset++) { + float v = LM[offset]; + for(int row = j - k, n = 0; row <= j + k; row++) { + for(int offset2 = row * width + i - k; offset2 <= row * width + i + k; offset2++) { + signs[n] = SGN(v - LM[offset2]); n++; } - - if (k == 1) { - contrast = sqrt(fabs(LM[offset + 1] - LM[offset - 1]) * fabs(LM[offset + 1] - LM[offset - 1]) + fabs(LM[offset + width] - LM[offset - width]) * fabs(LM[offset + width] - LM[offset - width])) / chmax; //for 3x3 - } else /* if (k==2) */ contrast = sqrt(fabs(LM[offset + 1] - LM[offset - 1]) * fabs(LM[offset + 1] - LM[offset - 1]) + fabs(LM[offset + width] - LM[offset - width]) * fabs(LM[offset + width] - LM[offset - width]) - + fabs(LM[offset + 2] - LM[offset - 2]) * fabs(LM[offset + 2] - LM[offset - 2]) + fabs(LM[offset + 2 * width] - LM[offset - 2 * width]) * fabs(LM[offset + 2 * width] - LM[offset - 2 * width])) / (2 * chmax); //for 5x5 - - if (contrast > 1.0f) { - contrast = 1.0f; } + float contrast; + if (k == 1) { + contrast = sqrtf(SQR(LM[offset + 1] - LM[offset - 1]) + SQR(LM[offset + width] - LM[offset - width])) * 0.125f; //for 3x3 + } else /* if (k==2) */ contrast = sqrtf(SQR(LM[offset + 1] - LM[offset - 1]) + SQR(LM[offset + width] - LM[offset - width]) + + SQR(LM[offset + 2] - LM[offset - 2]) + SQR(LM[offset + 2 * width] - LM[offset - 2 * width])) * 0.0625f; //for 5x5 + + contrast = std::min(contrast, 1.f); + //matrix 5x5 - temp = luminance[j][i] / 327.68f; //begin 3x3 - temp += CLIREF(v - LM[offset - width - 1]) * sqrtf(2.0f) * s; - temp += CLIREF(v - LM[offset - width]) * s; - temp += CLIREF(v - LM[offset - width + 1]) * sqrtf(2.0f) * s; - temp += CLIREF(v - LM[offset - 1]) * s; - temp += CLIREF(v - LM[offset + 1]) * s; - temp += CLIREF(v - LM[offset + width - 1]) * sqrtf(2.0f) * s; - temp += CLIREF(v - LM[offset + width]) * s; - temp += CLIREF(v - LM[offset + width + 1]) * sqrtf(2.0f) * s; //end 3x3 + float temp = v + 4.f *( v * (s + sqrt2 * s)); //begin 3x3 + float temp1 = sqrt2 * s *(LM[offset - width - 1] + LM[offset - width + 1] + LM[offset + width - 1] + LM[offset + width + 1]); + temp1 += s * (LM[offset - width] + LM[offset - 1] + LM[offset + 1] + LM[offset + width]); + + temp -= temp1; // add JD continue 5x5 if (k == 2) { - temp += 2.0f * CLIREF(v - LM[offset + 2 * width]) * s; - temp += 2.0f * CLIREF(v - LM[offset - 2 * width]) * s; - temp += 2.0f * CLIREF(v - LM[offset - 2 ]) * s; - temp += 2.0f * CLIREF(v - LM[offset + 2 ]) * s; + float temp2 = -(LM[offset + 2 * width] + LM[offset - 2 * width] + LM[offset - 2] + LM[offset + 2]); - temp += 2.0f * CLIREF(v - LM[offset + 2 * width - 1]) * s * sqrtf(1.25f); // 1.25 = 1*1 + 0.5*0.5 - temp += 2.0f * CLIREF(v - LM[offset + 2 * width - 2]) * s * sqrtf(2.00f); - temp += 2.0f * CLIREF(v - LM[offset + 2 * width + 1]) * s * sqrtf(1.25f); - temp += 2.0f * CLIREF(v - LM[offset + 2 * width + 2]) * s * sqrtf(2.00f); - temp += 2.0f * CLIREF(v - LM[offset + width + 2]) * s * sqrtf(1.25f); - temp += 2.0f * CLIREF(v - LM[offset + width - 2]) * s * sqrtf(1.25f); - temp += 2.0f * CLIREF(v - LM[offset - 2 * width - 1]) * s * sqrtf(1.25f); - temp += 2.0f * CLIREF(v - LM[offset - 2 * width - 2]) * s * sqrtf(2.00f); - temp += 2.0f * CLIREF(v - LM[offset - 2 * width + 1]) * s * sqrtf(1.25f); - temp += 2.0f * CLIREF(v - LM[offset - 2 * width + 2]) * s * sqrtf(2.00f); - temp += 2.0f * CLIREF(v - LM[offset - width + 2]) * s * sqrtf(1.25f); - temp += 2.0f * CLIREF(v - LM[offset - width - 2]) * s * sqrtf(1.25f); + temp2 -= sqrt1d25 * (LM[offset + 2 * width - 1] + LM[offset + 2 * width + 1] + LM[offset + width + 2] + LM[offset + width - 2] + + LM[offset - 2 * width - 1] + LM[offset - 2 * width + 1] + LM[offset - width + 2] + LM[offset - width - 2]); + + temp2 -= sqrt2 * (LM[offset + 2 * width - 2] + LM[offset + 2 * width + 2] + LM[offset - 2 * width - 2] + LM[offset - 2 * width + 2]); + temp2 += 18.601126159f * v ; + temp2 *= 2.f * s; + temp += temp2; } - if (temp < 0.0f) { - temp = 0.0f; - } + temp = std::max(temp, 0.f); + v = temp; - n = 0; - - for(row = j - k; row <= j + k; row++) { - for(col = i - k, offset2 = row * width + col; col <= i + k; col++, offset2++) { - if (((v < LM[offset2]) && (signs[n] > 0)) || ((v > LM[offset2]) && (signs[n] < 0))) { - temp = v * 0.75f + LM[offset2] * 0.25f; // 0.75 0.25 + for(int row = j + k, n = SQR(2*k+1) - 1; row >= j - k; row--) { + for(int offset2 = row * width + i + k; offset2 >= row * width + i - k; offset2--) { + if((LM[offset2] - v) * signs[n] > 0.f) { + temp = intp(0.75f, v, LM[offset2]); + goto breakout; } - - n++; + n--; } } + breakout: if (LM[offset] > 95.0f || LM[offset] < 5.0f) { contrast *= Cont0[unif]; //+ JD : luminance pyramid to adjust contrast by evaluation of LM[offset] @@ -730,184 +706,114 @@ void ImProcFunctions::MLmicrocontrast(float** luminance, int W, int H) contrast *= Cont5[unif]; //(2.0f/k)*Cont5[unif]; } - if (contrast > 1.0f) { - contrast = 1.0f; - } + contrast = std::min(contrast, 1.f); - tempL = 327.68f * (temp * (1.0f - contrast) + LM[offset] * contrast); + float tempL = intp(contrast, LM[offset], temp); // JD: modulation of microcontrast in function of original Luminance and modulation of luminance - temp2 = tempL / (327.68f * LM[offset]); //for highlights - - if (temp2 > 1.0f) { - if (temp2 > 1.70f) { - temp2 = 1.70f; //limit action - } - - if (LM[offset] > 98.0f) { - luminance[j][i] = LM[offset] * 327.68f; + if (tempL > LM[offset]) { + float temp2 = tempL / LM[offset]; //for highlights + temp2 = std::min(temp2, 1.7f); //limit action + temp2 -= 1.f; + if (LM[offset] > 98.0f) { + temp = 0.f; } else if (LM[offset] > 95.0f) { - temp = (L95[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L95[unif]; } else if (LM[offset] > 92.0f) { - temp = (L92[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L92[unif]; } else if (LM[offset] > 90.0f) { - temp = (L90[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L90[unif]; } else if (LM[offset] > 87.0f) { - temp = (L87[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L87[unif]; } else if (LM[offset] > 83.0f) { - temp = (L83[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L83[unif]; } else if (LM[offset] > 80.0f) { - temp = (L80[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L80[unif]; } else if (LM[offset] > 75.0f) { - temp = (L75[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L75[unif]; } else if (LM[offset] > 70.0f) { - temp = (L70[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L70[unif]; } else if (LM[offset] > 63.0f) { - temp = (L63[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L63[unif]; } else if (LM[offset] > 58.0f) { - temp = (L58[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L58[unif]; } else if (LM[offset] > 42.0f) { - temp = (L58[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L58[unif]; } else if (LM[offset] > 37.0f) { - temp = (L63[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L63[unif]; } else if (LM[offset] > 30.0f) { - temp = (L70[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L70[unif]; } else if (LM[offset] > 25.0f) { - temp = (L75[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L75[unif]; } else if (LM[offset] > 20.0f) { - temp = (L80[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L80[unif]; } else if (LM[offset] > 17.0f) { - temp = (L83[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L83[unif]; } else if (LM[offset] > 13.0f) { - temp = (L87[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L87[unif]; } else if (LM[offset] > 10.0f) { - temp = (L90[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; + temp = L90[unif]; } else if (LM[offset] > 5.0f) { - temp = (L95[unif] * (temp2 - 1.f)) + 1.0f; - luminance[j][i] = temp * LM[offset] * 327.68f; - } else if (LM[offset] > 0.0f) { - luminance[j][i] = LM[offset] * 327.68f; + temp = L95[unif]; + } else { + temp = 0.f; + } + luminance[j][i] *= (temp * temp2 + 1.f); + } else { + + float temp4 = LM[offset] / tempL; // + + if (temp4 > 1.0f) { + temp4 = std::min(temp4, 1.7f); //limit action + temp4 -= 1.f; + if (LM[offset] < 2.0f) { + temp = L98[unif]; + } else if (LM[offset] < 5.0f) { + temp = L95[unif]; + } else if (LM[offset] < 8.0f) { + temp = L92[unif]; + } else if (LM[offset] < 10.0f) { + temp = L90[unif]; + } else if (LM[offset] < 13.0f) { + temp = L87[unif]; + } else if (LM[offset] < 17.0f) { + temp = L83[unif]; + } else if (LM[offset] < 20.0f) { + temp = L80[unif]; + } else if (LM[offset] < 25.0f) { + temp = L75[unif]; + } else if (LM[offset] < 30.0f) { + temp = L70[unif]; + } else if (LM[offset] < 37.0f) { + temp = L63[unif]; + } else if (LM[offset] < 42.0f) { + temp = L58[unif]; + } else if (LM[offset] < 58.0f) { + temp = L58[unif]; + } else if (LM[offset] < 63.0f) { + temp = L63[unif]; + } else if (LM[offset] < 70.0f) { + temp = L70[unif]; + } else if (LM[offset] < 75.0f) { + temp = L75[unif]; + } else if (LM[offset] < 80.0f) { + temp = L80[unif]; + } else if (LM[offset] < 83.0f) { + temp = L83[unif]; + } else if (LM[offset] < 87.0f) { + temp = L87[unif]; + } else if (LM[offset] < 90.0f) { + temp = L90[unif]; + } else if (LM[offset] < 95.0f) { + temp = L95[unif]; + } else { + temp = 0.f; + } + luminance[j][i] /= (temp * temp4 + 1.f); } } - - temp4 = (327.68f * LM[offset]) / tempL; // - - if (temp4 > 1.0f) { - if (temp4 > 1.7f) { - temp4 = 1.7f; //limit action - } - - if (LM[offset] < 2.0f) { - temp3 = temp4 - 1.0f; - temp = (L98[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 5.0f) { - temp3 = temp4 - 1.0f; - temp = (L95[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 8.0f) { - temp3 = temp4 - 1.0f; - temp = (L92[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 10.0f) { - temp3 = temp4 - 1.0f; - temp = (L90[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 13.0f) { - temp3 = temp4 - 1.0f; - temp = (L87[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 17.0f) { - temp3 = temp4 - 1.0f; - temp = (L83[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 20.0f) { - temp3 = temp4 - 1.0f; - temp = (L80[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 25.0f) { - temp3 = temp4 - 1.0f; - temp = (L75[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 30.0f) { - temp3 = temp4 - 1.0f; - temp = (L70[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 37.0f) { - temp3 = temp4 - 1.0f; - temp = (L63[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 42.0f) { - temp3 = temp4 - 1.0f; - temp = (L58[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 58.0f) { - temp3 = temp4 - 1.0f; - temp = (L58[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 63.0f) { - temp3 = temp4 - 1.0f; - temp = (L63[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 70.0f) { - temp3 = temp4 - 1.0f; - temp = (L70[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 75.0f) { - temp3 = temp4 - 1.0f; - temp = (L75[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 80.0f) { - temp3 = temp4 - 1.0f; - temp = (L80[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 83.0f) { - temp3 = temp4 - 1.0f; - temp = (L83[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 87.0f) { - temp3 = temp4 - 1.0f; - temp = (L87[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 90.0f) { - temp3 = temp4 - 1.0f; - temp = (L90[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 95.0f) { - temp3 = temp4 - 1.0f; - temp = (L95[unif] * temp3) + 1.0f; - luminance[j][i] = (LM[offset] * 327.68f) / temp; - } else if (LM[offset] < 100.0f) { - luminance[j][i] = LM[offset] * 327.68f; - } - } - } - +} delete [] LM; - t2e.set(); - - if (settings->verbose) { - printf("Micro-contrast %d usec\n", t2e.etime(t1e)); - } - } void ImProcFunctions::MLmicrocontrast(LabImage* lab) diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h index 6e1138476..17a292618 100644 --- a/rtengine/rt_math.h +++ b/rtengine/rt_math.h @@ -87,6 +87,13 @@ constexpr T CLIP(const T& a) return LIM(a, static_cast(0), static_cast(MAXVAL)); } +template +constexpr T SGN(const T& a) +{ + // returns -1 for a < 0, 0 for a = 0 and +1 for a > 0 + return (T(0) < a) - (a < T(0)); +} + template constexpr T intp(T a, T b, T c) { From 9a1dd0109b6abbda91d4505cfdd23f5617d0af38 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 10 May 2017 15:43:19 +0200 Subject: [PATCH 02/32] MLmicrocontrast, eliminated one loop --- rtengine/ipsharpen.cc | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index 7ef323f08..7514a7eb4 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -622,7 +622,6 @@ BENCHFUN #pragma omp parallel #endif { - float signs[25]; #ifdef _OPENMP #pragma omp for schedule(dynamic,16) @@ -641,13 +640,6 @@ BENCHFUN for(int i = k, offset = j * width + i; i < width - k; i++, offset++) { float v = LM[offset]; - for(int row = j - k, n = 0; row <= j + k; row++) { - for(int offset2 = row * width + i - k; offset2 <= row * width + i + k; offset2++) { - signs[n] = SGN(v - LM[offset2]); - n++; - } - } - float contrast; if (k == 1) { contrast = sqrtf(SQR(LM[offset + 1] - LM[offset - 1]) + SQR(LM[offset + width] - LM[offset - width])) * 0.125f; //for 3x3 @@ -678,13 +670,10 @@ BENCHFUN temp = std::max(temp, 0.f); - - v = temp; - for(int row = j + k, n = SQR(2*k+1) - 1; row >= j - k; row--) { for(int offset2 = row * width + i + k; offset2 >= row * width + i - k; offset2--) { - if((LM[offset2] - v) * signs[n] > 0.f) { - temp = intp(0.75f, v, LM[offset2]); + if((LM[offset2] - temp) * SGN(v - LM[offset2]) > 0.f) { + temp = intp(0.75f, temp, LM[offset2]); goto breakout; } n--; From 442e5a3aa7fe0b1e817e189ac0088f65ee2a6836 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Wed, 10 May 2017 15:59:33 +0200 Subject: [PATCH 03/32] Preparing for 5.1-rc1 --- RELEASE_NOTES.txt | 61 +- doc/manpage/rawtherapee.1 | 11 +- .../images/{rt_splash_5.svg => rt_splash.svg} | 869 ++---------------- rtdata/images/splash.png | Bin 75666 -> 81929 bytes 4 files changed, 103 insertions(+), 838 deletions(-) rename rtdata/images/{rt_splash_5.svg => rt_splash.svg} (65%) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index aed4cce33..3e583f6c2 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,21 +1,14 @@ -RAWTHERAPEE 5 DEVELOPMENT RELEASE NOTES +RAWTHERAPEE 5.1-RC1 RELEASE NOTES --------------------------------------- +This is a release candidate for version 5.1. This is not version 5.1 yet. This release is meant for testing in order to enable us to release a stable 5.1. + RawTherapee provides you with a selection of powerful tools with which you can practice the art of developing raw photos. Be sure to read RawPedia to understand how each tool works so that you may make the most of it. http://rawpedia.rawtherapee.com/ A great place to start is the "Getting Started" article. Click on "Main page" in the top-left corner when you have finished reading that article to see all other articles. -This is a development version of RawTherapee. We update the code almost daily. Every few months, once enough changes have accumulated and the code is stabilized, we make a new official release. Every code change between these releases is known as a "development" version, and this is one of them. - -While we only commit tested and relatively stable code and so the development versions should be fairly stable, you should be aware that: -- Development versions only had limited testing, so there may be bugs unknown to us. -- You should report these bugs so that they get fixed for the next stable release. See - www.rawpedia.rawtherapee.com/How_to_write_useful_bug_reports -- The way new tools work in the development versions is likely to change as we tweak and tune them, so your processing profiles may produce different results when used in a future stable version. -- Bugs present in the stable versions get fixed in the development versions, and make it into the next stable version when we make a new official release. That means that in some ways the development versions can be "more stable" than the latest stable release. At the same time, new features may introduce new bugs. This is a trade-off you should be aware of. - News Relevant to Photographers ------------------------------ -- RawTherapee 5 supports most raw formats, including some unusual ones like those from cameras using Foveon and X-Trans sensors. If you're wondering whether it supports your camera's raw format, first download RawTherapee 5 and try for yourself. If a raw format is not supported it will either not open, or the preview in the Editor tab will appear black, white, or have a strong color cast - usually magenta. In that case, read the "Adding Support for New Raw Formats" RawPedia article. +- RawTherapee supports most raw formats, including some unusual ones like those from cameras using Foveon and X-Trans sensors. If you're wondering whether it supports your camera's raw format, first download RawTherapee and try for yourself. If a raw format is not supported it will either not open, or the preview in the Editor tab will appear black, white, or have a strong color cast - usually magenta. In that case, read the "Adding Support for New Raw Formats" RawPedia article. In order to use RawTherapee efficiently you should know that: - You can scroll all panels using the mouse scroll-wheel. @@ -24,27 +17,55 @@ In order to use RawTherapee efficiently you should know that: - All curves support the Shift and Ctrl keys while dragging a point. Shift+drag makes the point snap to meaningful axes (top, bottom, diagonal, other), while Ctrl+drag makes your mouse movement super-fine for precise point positioning. - There are many keyboard shortcuts which make working with RawTherapee much faster and give you greater control. Make sure you familiarize yourself with them on RawPedia's "Keyboard Shortcuts" page! -New features since 5.0-r1: -- +New features since 5.0: +- Pentax Pixel Shift support, to automatically combine sub-images from a Pentax Pixel Shift raw file into one high quality image. +- Support for processing any sub-image from raw formats which support multiple images. +- Dynamic Profile Creator to automatically generate per-image custom processing profiles by merging existing processing profiles based on image metadata (Exif). +- New command-line executable "rawtherapee-cli(.exe)" to reduce startup time for command-line operations. +- HaldCLUT paths are now relative to the HaldCLUT folder as set in Preferences. This enables you to share PP3 files easier. +- Auto White Balance now has a Temperature Bias, letting you make the automatic temperature warmer or cooler. +- LCP correction works for raw and non-raw files. +- LCP distortion correction support for fisheye lenses. +- Certain tools are now hidden or disabled if the loaded image does not support them, e.g. the tools in the Raw tab are disabled when working with a non-raw file. +- New zoom levels for the main preview in the Editor tab. +- New Fast Export option to downscale the image before processing, to increase speed. +- Custom crop ratio. +- Automatic monitor profile detection also in Linux. +- Lens information support added for Panasonic cameras. +- Support for lossy DNG files. +- Support for compressed Fujifilm Bayer raw files. +- Support for compressed X-Trans raw files. +- Support for Sigma sd Quattro DNG raw files. +- Added DCP profiles for accurate color for: + - FUJIFILM X100S + - LG Mobile LG-H815 (LG G4) + - NIKON D300 + - NIKON D300 + - NIKON D5600 + - NIKON D80 + - NIKON D810 + - Nikon D810 + - OLYMPUS E-M1MarkII + - Panasonic DMC-GX85 News Relevant to Package Maintainers ------------------------------------ -- To get the latest development version, use the "dev" branch. -- All development now uses GTK3, requiring version >=3.16. There are known bugs using GTK+ versions 3.20-3.22 where scrollbars may appear stuck (issue #3545) and where the Retinex tool's "Gain and Offset" panel may appear under the "Transmission" panel (issue #3525) until the user hovers the mouse cursor over a curve button. For this reason we recommend using GTK+ 3.16-3.18 if possible. -- GTK2 is no longer supported. Use branch "gtk2" if you want to compile a GTK2 version, but remember that there will be no improvements to it after 5.0-r1. +- No significant changes since 5.0-r1. +- Requires GTK+ version >=3.16. +- GTK2 is not supported. 5.0-r1 was the last GTK2 release. - Branches "master" and "gtk3" are dead, do not use them. - RawTherapee 5 requires GCC-4.9 or higher, or Clang. - Do not use -ffast-math, it will not make RawTherapee faster but will introduce artifacts. - Use -o3, it will make RawTherapee faster with no known side-effects. -- For stable builds (RT5) use -DCACHE_NAME_SUFFIX="" -- For development builds use -DCACHE_NAME_SUFFIX="5-dev" -- Windows builders should compile on a drive letter which users are most unlikely to have, such as Y:, due to the "There is no disk in the drive" error (issue #3544). +- For stable releases use -DCACHE_NAME_SUFFIX="" +- For development builds and release-candidates use -DCACHE_NAME_SUFFIX="5-dev" News Relevant to Developers --------------------------- +- Announce and discuss your plans in GitHub before starting work. +- Keep branches small so that completed and working features can be merged into the "dev" branch often, and so that they can be abandoned if they head in the wrong direction. - Use C++11 - Code must be run through astyle. -- Commits automatically trigger a compilation using Travis CI. DOCUMENTATION ------------- diff --git a/doc/manpage/rawtherapee.1 b/doc/manpage/rawtherapee.1 index bbd2a4f44..9b2469475 100644 --- a/doc/manpage/rawtherapee.1 +++ b/doc/manpage/rawtherapee.1 @@ -1,4 +1,4 @@ -.TH RAWTHERAPEE 1 "July 05, 2016" +.TH RAWTHERAPEE 1 "May 10, 2017" .SH NAME RawTherapee - An advanced, cross-platform program for developing raw photos. .SH DESCRIPTION @@ -14,11 +14,14 @@ RawTherapee - An advanced, cross-platform program for developing raw photos. The pipe symbol | indicates a choice of one or the other. The dash symbol - denotes a range of possible values from one to the other. .SH SYNOPSIS + RawTherapee GUI rawtherapee Start File Browser inside folder. rawtherapee Start Image Editor with file. - rawtherapee -c | Convert files in batch with default parameters. - rawtherapee -c | Convert files in batch with your own settings. - rawtherapee [-o |-O ] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] -c + + RawTherapee CLI + rawtherapee-cli -c | Convert files in batch with default parameters. + rawtherapee-cli -c | Convert files in batch with your own settings. + rawtherapee-cli [-o |-O ] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] -c .SH OPTIONS -c Specify one or more input files. -c must be the last option. diff --git a/rtdata/images/rt_splash_5.svg b/rtdata/images/rt_splash.svg similarity index 65% rename from rtdata/images/rt_splash_5.svg rename to rtdata/images/rt_splash.svg index 8f556f37e..ab983ad13 100644 --- a/rtdata/images/rt_splash_5.svg +++ b/rtdata/images/rt_splash.svg @@ -15,328 +15,15 @@ id="svg2" version="1.1" inkscape:version="0.91 r13725" - sodipodi:docname="rt_splash_5.svg" + sodipodi:docname="rt_splash.svg" style="enable-background:new" - inkscape:export-filename="/tmp/rt_splash_5.png" + inkscape:export-filename="/tmp/rt_splash_51rc1.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90"> RawTherapee Splash Screen - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 + .1 + + candidate 1 + Release + 8k0qc^|*%saDlf4_Fmo(t#P z3DZ#Fe$chHKL84z3%;Idri%8L`;N`EMCHn7h}BmhiW5o1tvL0VeBs;RG_Y);(1Vtx~t{_ZzCN|qkc_OJGBzpWhN9n8kF!?Fb9-_?v2iuvx~7i zqI9ifHNExAu5_+6f3+U0H(ok6I=a)N2|FJ^GQnI1;Fk&qoyqYVC$M=l_$4S-p{MSN z_s;KYb=#lw#4I#l{cTD-BUm32@cN>Hw?dRRn6+XQT)V!xi+kFFVdC{R$;1fQO=6&8DwuT;ZO-op&n1kHw)TnF z<8j>_AbmS^8qOf|T#uIq^u)n;S*O`v8ZVtOTtD_9v;E1S>Wp=g3m(bm6%QRK_?Rki)#SMg) zmL5D)G2x}C4S2=clrI0$@`E6!tQBG@ngAgvc6yFroU2y$**u;1Ni+89fN5GUvSwlc z=zfv-g13ePQ1lTsV$jO89!{WrGu_clVNR^9BsMB>g>2>%t8^0Up&<8Ow18Aw_2J=zChIOW0Ou=U6Gfht&X(K0t7;7h~m@6FKhm9lk+3;z0xBq_N8#OuxM3Smr z3@5K$E3;51uWirvUlhS|UtbLP8*JTts3SD)I3Afs#u4)?l4q{9wZ!{BRj zs{kI4;Fdf>E7^Av1t}$lwt0GeGnQ4k4eLlZo zTj2gAr@Yz?7sxXZoykLPaHuc5Xlo#}CY2r~BIpF)4k%!?4}hgrN^u2bK^WyOel-f+ z1M|VBue5Zp|FTf zaBk=-nKFIpdx$4ZB#t3rp5sHDTSX*SF!)i-DPdy~_0LDgnwe|lfd+M{ypDjsZLOn%av1Xt&jj1dxWpM(ZX2JPt%SXfNdN_!dCKYWy#w2g>&Y9u@S)R2i z1`4JweKP!hZgh@=78(a74BOmb=S-HA6jtnvDrLmCgLnK~?fnFJMPI9FzL62V+?(0( z$>M&JSM_1%rkRck8mcw*SeA6dbl=|5NEhRI3T{m zwJ*lMGABV;VW-+*E>eyKDR&J95&czRvZ2$?JLcp47%^*2Xv)V+^4w{s*Uv&Fqq$F3 zHUrbRx6BJ5uiqpo{NDS^VmiRRDH)byyNP*7;+4r%*;BtPLcDA*COJZ+Y!4-A3z;RA zp$)t(i3j`{-mk@IOV4u3oRcETF$wv{- zqhx=Ot+f$n%J+=aedVoIvFM++|9J{PC- zxozJ&mmKuT#23h+$jT*oD^yhaoq4C3Unzk)QJx;XC5L)5n;>PHl0`;z<6ljwEQ>XD z?rq{-%Rzl<7~U9c@uW*VrpcWI8l3zJ)5i?Bp z${;AKf)_y?g&KNq-v^tV7x}P+umCC!X6)9y9u`sKz=k{8jgY#RQELVNy&%OvabDBX_@Hut5 zZ~ug;ZnmJz-#%SA$zo;@=@1kUj$XEa?MUDnJ{cO#Pva)NU!q}4Xkw&SmU^URLt<1& z@V3fmJ8-3xKMTlDbLk*67D4dJM6v_;rWBBMx3;&XeIL>zJMTx-QO>dJrxWInimVY} ztSS=X+Q}hlv=ZF!qcsF*G)j6c0v%ViS80D$W*ESaRyciMG#zn;+|W{iLTh zu9+rrEzV+CGox6ql%N1A#(+So_7hv7AFLA~DI0p;CzK|2(D?%U- zE{VSIJfDF9g7*Ho-o7a^4FFx|?UTAyqxI`{WmkC17ZQ@cJ4fHOVf6)v_G$1O4SxKk zk-8p4(eO}Ioo1ktt;D3`g@wuzD(es^5XDdY@7r+4@1;ilA8_S-pi zUd;+ZHHx$(Ale=9IyNcKPUAMWQcmQSqr=GUy5c}#9q6$T9J?lyQbDDB zJsgj$r3PLp{#FbFb(CmJF?%+ko8yfKs(s6xZ!kF0IVH_ykM_5wya5Ltmh3zHY-Yu2 zD9v8WB~otb*m6!TDf2Q;1JaPq?Df1!XP4%#n<;1+e6Tn*$hUz_9^I^~+cM@@+}-9& z<<>!+KH-{_6wvU{NPuZTe+DsAC=dB#;s`>3Tn|IAvpk0?Wr9_C0?0N~73`B{g#QI5 zz51#2L5+yx&7&LnYCi-mhy|9t!7RLP9rSkDERb z`P+fkb8rjJDemuUyOlYa-x*E?4GZ0P*#jm^#~-bv68EPXfT;TRwid_4{T=_Xb1KW@ z0eu)|P#LYItP^iHmH^XB#K4MGpHV26m4XzS9tEA%B+ zFrqxRp&8ZM_hoI5tM&baj=f}+F-${Ue=4cc2C9Rwnc_Q(@l^e~tj$H$nn}8#n)!In zj6^7Lm+w`)%p)Y9a95Yq%MH6_UC5cm%4;KH@Ed^YXboa3sB;QXp{uZt)OmeiW5eIz z7!ej2TSD*2Webz@Z-r!lq2UOcTuy;9-|vz07ndGy7oPkVWkwgJJbIq;U*F6W5BLz# z=RNtCWu5e(V$-rN-CKe^ofSk}yrq104vM;6flo`^aYK-gGRkinIAropHo*2sx?J)N z15`pcqkqA4`AcIIF-WnDB5Vr2m=-wQO07EQiZW)Ki$xe3pF0!IJ#m^%vhv+kxSfg3 zfva!+F*Ff_ZiBw616PwzM|Av|2?ugBbO>pqvw?Aq`rZl7NuiE(hGYIwzb)nz{PC8q zgj7KC zSq8RYD-Mswjy;idtj5FHZeN%v*|R$>BPufkbj_ZwM&$E$O$`KD^4d>j@Fb9J;TC5OihX7e4p^D?uN3-j#xgJM@C31`f1%(gZP6)lzR;D#7=)KTM@zDxH z>1?(qcDP+0Zsu0rKAYD#xVQ#u;#k&wmHbK*mP8VfhY26gN^KejU<|~64UhIWBAdre zTJlNqQ`T~OEB<;c2>n_RlHi|+G!aB{`$=n4@&Em2t3@w1a_u)hG1IsHzv@R*F|x3+ zcFFZ#$ib*Uq_Fbz%%lG34#ERax)Cb3)EEtPx884Ke>+Y0sJMH~si@q#12=k$GR39U z8E;Pz4f0v$PmlpzkjUVt`1B-Bl);lG`}40yjG%{XceEOe%&QQ|9*US4nt=;J&=Wkv z#V^Mz&*E2nF0?zJ3}=BwmIAyPc+ zK)j~mjz5STGmcucC}@O1X0K2BqQm_kxTgPEOY+~iUT4YY!5l^KYVy%Aec_1 zEawVWU1>1>UX{HZ76;QZ2Ww9FQt*{1keX2SKmhtKWRpiPS}D@lcdPheCg0?i=vRS< zGa;$nUZEZ1zf3Sbt~H|q*79a0xw~hG(@HvLci?zk%kdjq#azE=E@0Pt2TF$vI?_8J zs}!rF0YozNZF(8oAvvPJdx)r7>q5VhT0OhTzaAG9?ms!dct*TaGKztj|`{gGxDje<*%5_{mmLpBV4}ILM zaIH64NBxcXQ)I@E!4xN~5>tRts78dkMCkMO0j_Cw$Ui8|F|7KegRrr_sek{97NUJS zROc{7Y1-B_kva{ew?w~lcRb)9YPYKt@w%T1SP>eA~Q ziZ=9OqkwiTTJ$XuTAd{}Gh~VCj5NgwpOnEIn zxw3X(exc@X{7MdaEib#3oAvS&8bvf8&I-!DLRf~PMTGVfC6^{Bq%BkR{K-yMk#d2W zGs-8xTs90LDqQXQ$%cgVPsZ>x5Z)36yi)VI5pHk$2>HQcqH;{xzBmYO3>HCc?Y&~* z2(|=}pMvAP;l%6bl`KhAccHn+tbeoAMLz+$8Somm3ccJ@D_H}v@)_;hrr zBAp!s=inTYr>yX_Ae*4Uob@s~UzBvIbL+Mr?U>QoOx-vZ?Evlx+a<@&Cvdi^|T>?3++ucrRqjcaQzvI&DM(>-&Td`cX)Ba4VX z#-dSrb`4Gz>6;&C5L6eqb!XB`(S}@78ei+rq*iJsyoMVnj|=?3fp3X2FQ+&We8maO zw1bw(sy89hpY-PeS&W~xl<++pENagv2SZh`Y(?VtQ*FBCFkWZ5s>^Pklp$2+0nW?Y zUU5x*%R6ysOIM^D{&OE#mV2rxzErptzF^<}sDfir8~RM=)yg4u`x?R&`Iqkt<1yA* zHcEOYS@-n}kd{IFz|AT87z4*(<@1%cwj%b5&W?91V zJ%x6_$8^>dt!;&kn3EaGpJNj^UnaTyqhqD9&> z+R=AsVgo4>c)wSSn{%SdcF%4>i6NkYK$Gpwg9@pWsiM$tePAHOe(k{Lbq=e7d_m|+ zx&s!d!1^@|-ry<{Q57T}Z|kI#<7SE2lYnBoXw);$e=Ox2zh?=UZ)FEV!n>N@iH*8U z?F{X?qOaBz2lQeoWd{;`7JHfBnq!8ykRV9)xXH-?caj*VdHwXI`rqd1(slP zH9JT}pm(?QBdgeolOX>oq&+s4Hd=nVEQ)5d!h2!7HfW0+63+^+@8Lo+B`2(zdGZN) zeSI=1y^td$BUnqd_1K+?YoG)J827|ih`jPv;l7g!^_&#U6m?9d0~|I2FhDC`LiNG# z7f71V*M@7}OMgptJL6PwIG8vhMVQLl=Rx89SYV-!ho#Ebh&5T)$UmvD*Vbpid>H=V zq*$7g{;zLB7S(@dN62vy!pE#p$dpdg0;xDdyvZ>L-RBtDu?U&LHL*YzK?I`CrC+4N z%VjB}Z+buEXAn3A>+$k_so=F>8RYv$}eQHK9~ z-VKaQ><>l`-bsmP>#>%?Uk;TKu=F&{By1^a+eL)6v_D$C9Q;>OR%NnseB;q4i4I2k zI?5y`8$*?4pfU5Rq30l%ax{7B&f4B^TjPfc`T<2 zd-!wrcVoYqwGHIep67Ht%@dtmtDE=p@(P%qCLKDUoXr}eYG9JSr7(t5)`7HJsCw_{u*4f(63`;zXi~0cT|N^$$T>&&@rD$eEW#ZJaffn2Kd!g*WcIE;6d@> zy8i@w5VHIQ>mVOgtN&mv`unEoZ`z`I1E(m>ofd%|Gk1HW!K>hQO}9IRd1wMG?f0yD z>YXb!v&0?$i2H;12}4e3%7o=2siTanoUh+o>)l70+Q0t??|*GnwaBExEABMM1aR__ z;x2=c;WB0%;rn<4JFG@brCX;qaVYbF+vm^SF zTX3KwmZtk*O}2Tb?sl!NoNzdg8*-U?3>)JMsNOLSf*CbbP#KA`uS}|2=gnR!Sn2frJYFe`FX2O46(o{HT;vMRSkWa9{`oz{6BeDWfmQi;b(7g5Hb~z&0BO5&M zv3~6d3bO0`r?rAen6``P9ca-!`Tc(ErsC@ydEydtn4LTG*5GTBOBs4;VIg?L1Y>3dngFs;vhil1O!gpFe zPVe(INzLp99AX-t8h!7OU_qAYxywWJBX+T8JR7K0CLkKpdv(4`_K)VvgKfR;a(>zp zE^Lbp(v!Xd@$dQ3iV^fk-~Y-w9y3)xWv^EuhW@yAhOMVF zGa1)^KYm0YdbvqXVhJZ#c?_ZlVa`;o8mfzpFi@r$D+Q=vwllU}sw)^Olca!bo z6-1H$V}s!Tfg|4USJSX9c~uZXTR>S#UL*DQh2G859rE@ z6#8BkB@a`L3+^cB+3C`P`XsVa z*@93oVeZgh5jAqQa^fG^x}A~;L__ryJXf=^w?-F*q|I4^V3wT$Lgjx}4p>l!So!o) z@$w|}?^Rp@lm7fF8@qpwexxkAWpas^KsV!;S0M{>mXEbb*A}AcN3y>VMng8mm>BpH z1=JgPyGG}N4z1gBo(@Z47pyhZ5BVBaaF_SksB)|VZ%z*b9mg?4ij$_ z4*MMX!7JB_)5JysXtr3zzp0b0oBxM~$#!pSj_(18_ZVre*Wl^vzA;6w0B*-0rk4^Y zjHy(gsl(HB(j}aueI{W&EG}W!9mcT0?-+pF6DqBAq-di+^n~}X0kxC51RdY<-J2bl zh*B|EJRa{L2;Z>dqjCE}PO@x?jsLEi3Tez=O|D%d1Eb0P9798q*9u24M0ilxT#&Af zy%nH_$9Qd#s=&<3e)EtG`iNB~1_ibsK^64AW|T`cu#pgFJ|CREd%oh6jpnwOSD>f9&% zaxOobD5b4Z+p$G*NqHLN&6?ti(n)!=S4;{$o6@)m*TO3srA zd)hAoCnM3N7a^jeNne93pJkgjF*-J!&Z00>;<{YO^C{a=xu};7t z35CtWCylUd;&S&C;Vvv)@_Yg~(u)RxSYVxgB zsQU3iKCuhg+QZ*49_1+LWb~r`Ch*6Nu2wG{YNmgy_T5&FtGO9gSr+`W3d>XHmG<%| z-sx;c(!?hnZT9WCb8ds2IRn{7?jJB9E>cfb;9jmLgRo!mDYQ!dv){|kT267G&9D97 z0xu6F=T4$UL>x|M;YH8gaK?LaKRMO} zV=aV%)eGYTHV8AW%q&W@C0f4V5ghau%l>Pa(B8!6u;f(HCUL{uK>Y|-!~=c=hjVep zz+mK`PWzWUjMdAHK_Oqe$QmK8M30MK6Bp#S2cw!v)T-Beei210)r_@h_*?__!8xCU zbB1L1bJ}FpdVLxs9nzoG01X{i$d=2b$DvfJ_F%=&8y0yfH9Hn|JcIu^eEsp1$A7f8S2Nu#8XNuCs>+rqlMA zFFEEmYE{TDsB3xZbS7&|LhX8H6indu%Sbp$;2khe;Ppc=pIg+!1E>;TL!c#4QE0Z) zs3jsL3VZjxGPCgSE~UHqugr_LRxQ_NyCe{f1x?>poK07H>9iX@{=nRinAjAN68HHE zjK8wHp)*w@+O9sSg}l+g4_O>A>KS_9W6${{iU=heYB;d}^1?myF^#(9?w)91ns)qH zH?|BdV_x8ATl%>r(Vqr zz3P;1F%5;La-vJsYPSqsC2bvnHAeK8fcJ~%=Rc~}*kIJ$IDGc^3Qx^F^oin*OE}-; zviY5pl2+ifit8wk?;SR8?6lK>|)R4vBMx2uoSG*wY;dmuP(Dv z2T}upVtz|^-lhHMiIK0NZQl+AeX@5;51+SNzTEn&h>8uudkbud{sYV4=#?)(W^!W> zCA3kDwMV!AQX+=n!yGL55qoXK)UlQ!o(KrH!rU{_lTn^h%?x(CjD^O#yf)-p z*29Y?g3T>+y6(73){*riT&apA8Nms@&$J{oBOKT28K@TyIZYW4Dg${P^=%U65FIIdLj8``=U``AZrpjD{Dr8FAoDUp%mqUfisIcK@pPV(`2=7P0 zl(jlgBPy<44-ygaOZ*YmO9BOK=io3Aai01YQlBNqd&X66&|oF;I$fL*`CxDd;^Xq9 z2bS!Rw0VA!_O)Q6?OPKM0Kl26q^w4cx~m>uX0z$NW?jqj-g`KS1&!eA9)HhU84j+? zcDGM-uNB=#rRirI6hN{>C+nP>#rHK2lt=>9oqGT5HQ$_P{&wB0H(bSt*^d30H-y%- zqHgm04^N-qk4#q5Mt!^M71dBgwpwGE{%yMPj3Vr*!?s3FsG_(c;4F;BTgT*k`78|! zkz>zxHCs(lf?VSN3UKyIUhDRfKZF(DDb}+SdMTTqnk@-Na=XS7>zD6RY61uj7XzRj z!+9gTU+1f-M2G(QL632OAmto?cd=MeM&8%GUt419a&c&lHN<``2!3y zYJ}D2YfEtAi33Qbz>2z(9i27dg3M-Ka2SPS&aygwF8SL^wd|VsH#{pu69Ib5wUz3FS zfvetp7$sFGy#1}h)pPO>dP;3~hqnHBH_ozQ3a~;cEWn*5_&iS+!PFy81&X}OKPoT1 z4MB8R(&;RMVFI$01owAP0>niODkP zi@BTt_?hlW=pCEE+^s4mjQrd@Y#;O*)00K$(oFWs2|OK^V+vg?QQ zKKUCPR+-f=!5y}+4)2+w4wXvEYeub`w~HqskgNHZ)H(JW-=`bh$0gp z2IoE=L*~-$TC+;^`YT6cmYFMG?(5Rf*n~77rEM#;A-I2bf5^>yrSE#Nc3$#iON=V` z&zz|%!HI54SgbqO%0F?(gsd+o!HUA5!o1_cNPM7^*FB-fY^5q7E7q&tmF_pRz+f!H zI}Ffk{=60Q!p&MA4P_BoM}%ajJ4$P=0l<o zmcB;E@z4w@=W9|5jNQB(5LvxzZq2zhHiTzo~DV9-9PuD9YmlB>GdE^&fbAGCn zVuFs6sD9L;m0)V)nL#@nvchhg52yw@hW849ZM5UE>{jS?Mm-4%!yn*NcU7o=d=W#O zW^(3!U&@Pg`re&$E#R7cYyK6thtwaDwt0L(ycEK>p_B7hfM zkgc02SZ2|xLsM6p0uT6az0$;qLh-UltF4SH(@&1KOo|t$0|#X~!rgKO63YRyfx9<> z5$#Ab*=aHNaI3c;Ndbv?VEMZJOy2rm)A%L=%*IzxB{;ixw~2k8kjf71zYEtza#?VL+&(BcAo?)Y8Xq!MI;Pw;t2da>!= zm@WBhmyL|mJ`ilh*yHx(Mamp)^J;DvT&kajh@HqG2yTH2oAW!3I;ZgtY;u});(qS-!hau^LiqmMc@@qEnc@7#Ic1UM_q9M_=joEV?-|hXTe7EZ zNv8@h-dau{2uS4a*wGWFeC)&olW?y=ILRX&q0wpL?(m@yE>T!!USvs>{=+xy^2=rh|b@x(`{1n8&XAX?`Ku;m_S}^nC$WDP;Ao_zEr~j(C$*kn$y7CT5f}HpMcPV>v)V zVR1GbR=*)IWVm)_A*TE-5mmZJDWN>oTL3aIs4rw^9_ta~?SP(D8|zM(8`_ElHC)JyBVI^1j(CDYI3pb$&=hfI6U zWlz0VfwKqP>Q$^;7a73%fn%^>!EXLGD5rDv7g_xHFgt$qsP;{Ub;}B(rUaB`!h^{% z6EaA{q4hM5JcFuf5;BU2^dgxV4Hhv*E*h;_^mF z6<`w#lGBoglR6jC-v+2a;z-YP<^EGmH{i2lL(Ku`@tQI!LI!=dt*0w<|Dd+-{_$ePQ7PLmCn|h zl6zj7Q8vAQq9{?89)w58Mo2Xa8>VJZal0&b!;{h+sPdC=)3gnI)?CB?#D@atOu>;% zn|B0yt55C0Ecu;5K0xS_@p$v8k~-CHvsNb?)5xfK&edV@Y1I)Jez+osg5GR@@ZhaT z|7Iv890&Qe?Ugl8q&uhbORto>9>V#7`B>$88ZH(r(T+l)Oy%r$DJGD)j5_#-VOZKo zTp3a?@y^&Xpo~sdARyz#c0e(f08Z)1Gpekkb4xT%vJ0juLvB&GUA=$qB+Zk7p;SGv zHN=6a3PT#hI0+J<|20QgY*TqsQY;4}-#GKfBW{*ui62&zm+`~KE%vVk`!kd8DOyGN zc3B01d{@WULvmQ+n_iYIXRnpuqAxbv&y0|)Rw>Z?gXUCVJY$utAA`piJ_t7Dp&40g zIH<;&HWaQN;5`L(TeBN{!)5+S-2GZ0zX%Sn3kdqQLxEF3VzD4#-TXf)NEwSPP00KT z|6W6~JvMl(9~>*Jf$c@UqyW9S*E>DGytu??FC@C##LnKCyC>R#E`&-y*|>nr4tJX5 zm(D)}*Bf?c#|5kXZz=okq)?zGO=c4IskbTjaA4_&Yt&guAv;gbKF|zpI zHHBnGZ_WVHN?8xuur>uY3-#qN8BCx9?4<&?Ms7d{GEov z3!Y?HrBF$f!iif2T^yxzHMOE3=1QZFCUD%FB0s@?ypjS}J!j)q z5)ofaT2W$JY_3=H5$hl`j++sI+^S*piQkk<^5eQ98tJQ3Dlr)AS+Hq?x}dmqCA%&1 zko7OJS1nXE*N-3lXjGRtP1lNzkd!NBuHGwccyz`r3V);)gc5C$6{2)HhCd|!G6Jxr zsU1V#sLM>y|2O^Qg+IO`<&c*s$ClFAqd^;47Ct(Yj|wIj;wA$Hxtb?y!eA4v4Luz6 zF?J+cN3@h-)%dPY4T{qW30QI+jZlUNf>Baaxb2~VC6>H4(b&-i@x04%PJ9%W0fWtE zfsmqn3{Ggv$$?gZE)uR$%$+Vk+AmbCyaN2ZuduxQ*bZQW4MZ^K1(E+86Xi3GU3o`C z6034&-c+kuhVq(BWzn){w6)AUZ)ly^7XO&dPc;k?Q#V=+n4p)cZKtz~bu5HvTA!ip zGPn=!o#bzCHIt}oXXHNb%e*cyon3fdyf#f4Wh5y)mF*d2+|k`W)wm7=g08ev&JS-zF$ZI& zawx!i-lGVJ8JtMr77qaV2JwidC+9mj0(LRR2n(eCjv@EOSRbk{zFSpD(O;Im8e%%!EA~%{ z5nuO--o3gX+7wuXQuADfSvfTGP{Z{^hblayFiV5#-*taQaj*d4;;od(7>AV3$it5) zw@n&mPsy8IL%<{Y>TUK&*F7v)VXyp?Im568l(0k`{s=1E94|DnD7VMU;dD|`JS@-B zDYKy&@$%1j9jz@+sHER>5+2jnIQsluy`NX9%Dh|@<7+%eUAS`z*w=zDEP0zU+?FnMwSw*4p zx8!_9Nq`^fsLwudJP4kj09v5=CS0}$V_H}kQ$@shp96`@Q|yWvn-8ZS6-cz=j~*z3 z*Dq$n2P+{DvsL7dUm?-X>XJgLNDcdyP%KE8Y|{+O;`rzEES^QseLI*e_{0t}%Dph(&%h87Aj@sy7uW&g9PFQS4m9Xx`lmYL?#sFxy7cv3$YCuSQ2zv31+A z(PcjmzTlcu7WO0R6s1;zFbr^BvQ@~7kG?wAw}QYP)rRi>5O^EsZ#@4I6{hoZsdYXK zSztakrH58VWp-;f%yW4`&X<=n!nH|7A8u&MaAQR@b{n)t*2VD!qzEdjwibd&0l0UBh zWSA`+&cd6m!_9@zM*Ne27;_MQ;_O0owYdV?u2E4MQW5qNtM=j2hKTRJ8`W(#O}PpJ zZEkft4_JIpZZUCao-gX&lL=1Tv68wmyi;G*o^@cV^W|TEQ;xCzM}(RjEzmp<$iMYl zv_POT3Mj%O0g_xVwOFz}0mLbKQTeALfva@SS{fAL^l{r;{4@kuUTu2V8_i0K{K&e| z#naSIH!F9IT67bfxMb++y;S(%$jx|WXFHdXx^PjszM1>WEt$+{uXv`?wl4jS&o)2B z>nD-x8o5}l(eXE%u5-a7MS$$(7+Wqhh!dVb7D2rcQEk(*CH%DRexp@%09&+6zc7*9 zxlsZS>wROX_E8JSm`fpdh>Ac-PX-&&^g?$$lSZ&?tUDpL;r6u%n&z*YI7Y1UE^P-B zyH3CJBVQt+K7}=*221yKWoSEUoQ2%WYkR%3-Y!5eo2tE8Lt~p}ngOM>o)WP?Z+~fQ z_4N7H$8EnOtESw6PGc>4!lBv;b6ghmHfewg@OB}Y(v<;w5=A#VWqTnax=Cm-z|6J{+wCj#*6i6@Jc;UpD-8= zGHiwHiH{ny0wG*N7hUG%RyV=HPcrIiv18J-2TcF2$z%|(Wk{lr9PkgF3s_peuWv$q zq=Bu;B~8ngXxt2d->Vj7RlwfFFAcv1M3|)Sm`K|#k17k&ZJqEFkP$<4{Ty(8a)Sx} z5dAy4wW3m|bZ6Dq?4S-|E}i|Tmpq~HLMqC_N6MM+=)F;mu*5KmWE!@n)!A?FL=7GT zh^?5+!Lm@P!Iw)49W_mj8r5h$f{hrD{Dv9;K>ez)_CUosA&Dt4{|Vhx*wWCaa6p)0 zk4cbg61m;H&yD&ku~cPq@Ko@U?Og;IVU-F~x{1!Y>pf*AzFHPIRSgK0&~u@Csi~=k*OL&HBL)b`)h%GE4QjH(a~x~Dt0<&dgz0iP;UH>gQw5f0d7T8Rh$HZ9p^-z z7I)r%b6F@I!#5Zg@lus(APX0r2&EKK0^K_)?Cj z54HBl67?Dd^2Y^+{xPa2g;5b;H=Br6$@;B$bmQkoBAqR7LOjZto+CXZG^bsXB|XV@ zba*GJ)l+yUe(v6>!(Vf?W-K!$BIA9pLA_+KjyqM|yO{U~LM~jmf$e`@HDB-H>F}5M z{$f*l>$cy;aK$j-4trG-k{g5gpAM=a9UN$SEo&4~m78Z3gVhOKX(}JUMG1Jxc7Nmd zzg`MUzY%RXCv5K*3Qp{t*$G#>6%^e&Ligf5oVRHws#~Y-CMH%{}Z= zsWY0fD&Gorn_n!e1=*ZY^W7Bj+bNUz0~6R`&5gFb!(Qs%yXk~*CyT3TNE?9}A_#JaYn*$I{C%a6zsf%LS!&YYtT zn(csXuaz)UX$bOeL@@hjL}&pyRt&c8b;lvXHtM$0MbN)8OduvD_@j3baD|j|xm9`Y z6z%%0M_7!asH0XzoL82Ne@`vs(=AqS9T5kr`1vT z4t8TVIcjFmKtu`sLb$myD<6d4JE2Z8{+ixd30mgZw!Kc+k;48z4zfu`W)W^6&Eut2 z^~9v+TLg6Nd#mxF0IFdFhkW6H1*i2=X^Xy)7Cob_!4w3SPH8^?jq!uNagw5M^a-fv zV?pz16nIu4@ERJ|lY8c!5q|=l$bIo}I#52w<~=5@N;i1HAI-)tP#n=?D_Y~_Fj8;~ z;^abN;w9HIu6Il9bVOHVexN0ZG2Z5OqvhwLS+M5F=g!9* zq^D=RTq&=vt!=lO=L8$7)omrCF5#Us> zglDeS+&r_CNO8M4#0fq2;R`)>PhX?ncrdE!1ldS-Gny1^onfgXEUNRSKEgHRAsM?{ zA|YF-*qP~XcHo4Kko|EB$2A&E2JT_F5ckx;iXu{N4uA|BzzY z1poP<705he!ij6biKfSrF4ctnhn25kFSV*p-8N5x;j8*_)ys)o#3GrAg3sf(NTRJ% z-B_O6zDk6OcV+BDWY5&J+h(7If(9NKg6ESlA8ux46_KLv6F&Pxe%8|cFF65PRvbCV ziY-9DVJRov9DZ#lDFCN(T4L6+$+BscJPS#S%Hjm;Gdua#OXI>64hsoprb|7ETVhUZ z23cy90EzKuh&D#cA61cX5t=}0ggZjQ9rxF3-hWBVWKe;t=xfN5>)A;~AqG!E3fbD$ z?HYoI`!VS%P`I=a&ZL&OY)XKd9CaTR&?1a5*jgfNtgkD7;QU^CrKpl?Y(5emuR@Fe zO@awTnXWt>?$U4mhW26hx4F(w9-2TZ43komf`6&B(;3-&s%k$!p~X9i5~Cl0EZYGD z(GW_jqKlG_#HV3#KZ{wrft?L+8^*OwR7n#o;%IP;;I^O=6=t1nKx)fkJ+J~}oDEPE zivBdPq1T_3Nq0Z&=^Rm{-#CVmvS*Fm_W5I2BU+(gtpOpy@Dl!OCf^&ysVb_frmUJY zb#;s8?WPZ0q|kmOPvb_Z&I>b#@Anm2QQER=X@5^5hn1kh6sF*12B$a1%K{zz*DA2& ztt1kc`ce3_(A(7S`^vqZ3$}0X9IzbpB)b{izaXARCZ96~6z{uF zORcDilIu`siRr6lrt#MY&(HliyxV7HtQT4gNdz4c2u7IMrJ zCAbu%m*$Ei5Xi?=CI+9Nn()tVMMm%f_;iMvfcKUonn*)%!5*c=EC?-MD`-tTm(v)b zyu6(Ar&hw$Y5joMizZhBC3Va2lq;P#My9?UKdgVZWX<^9Ly>8(1Dzg05kxy5;uVF79GVMPhFIqJm1?@_a)_#N6d+0eE`Fz(&Y;1DabUxfzD$CC<)4vIN@RRit` zQ;sQpJFiO6zz>d`_(q5V6cfKEqQm6aE7e9XIV4tZoa^%n&|MM=8OJCU$UFm8n&Lk} z8`Cp`S};$3C9_4{grp6u<{1Rm7kMI8Xc((UD@|A|5RJ^sSH~Hs;%peEOu9;}bcjx7u+_%K=?GQ6y+Huk9@4-=ga9SKP*`K$g3WBB~u`tK)qjaWD{X+3A|YXT+2b+WX=6Uc`2E=y3C~HJ86Fx}+Yn~W zN)&jXS|TxGXJSRzm6ad;>k3G<@)1r1!d;+=D4i)=(QN^?fmd>{Q8FPnaN;Kh*M8__ zB|+MIRQ2T(Ekpnrao2*s%lnzeBX=4vd0iLQs0O(WI`~%gkByKv_+v;6XdQ2umH=sR zTZ`yHLZy<{p8?0$9z3BNZ zR}d%`mkg7e=}-yTSFx3isR5fhub%=}Z;J*(4t!W z<23F^6^9t<F&D9^(>QUvqv;$QQ3Q5=d16a}!^DKqrf&uO{zvgp^rE5JSOPULwE+ z9R#HRC>cZ*qEt9|AKyU({*U?~Ir3CL)TJ_!C7ycv_A_Uc*-i~$(7+)Hu+LM|4*fd0 z_ASGlxNVqJ$(&}R`-rq1$wz{T&1m9hQ{C9nqif9EDP>+_t4GK{4Q7R9ANhS)8QlK- zpQ^lwx#&dd0lE8pfFeF>MmiLNbXdK!;ljo_$7d?etl#U|iR56B`dDRqTg9m1YbXiU z0s1;)N8-WiK{Cek^yYE{;k;=$ypaum%*pJ&^lNTj6~6H3Jkk*qpeO`eA`~Nszhflv z2NN6rhT-HX=OEI(u$kVx^Vix>62=o1r0$5)I))S=M#7)&OQ2+8?S6pD?<% z{tOq=X8&%3;eQ6dy8oT5OyJ77xS2UHt420Q|ce00%I z2B8(G!KOb2cLJ0&a*B_U<4s+75-Zs1Xlq{CG$HoZNlz7F1{fCBEF+%65R3}UsL980 z2B~8&86-l2B8+$^R|PcVaO2>bhy&kbvO!L6)@q;BA36MIKp5+NZy9?Lg&e{ zANaf)&oVrY%F^DhjBj~>x=~J%tyX;EIo6eIu)Ip1s1R*{lHn6GbpV@7|6ZIznj|1) zH;?F}SBI*L3&hL!dK^b*lgXZg98ce{(Gxo{K7qdo8!j7w_4I*3!?ea?Q8#)~%j(AC z{IeNCy%xhMc=d%IU+-682zSi1Ry?j))2yknabQvs#zdEA_M$#G%XxpIrnXk5I>kT+ zoL)rURx^OBE(8Ui57lnT85EQ$8O+Zg1V7pw9FUOd!xP*;KQ|9|rj8ngNxJ*AJI&KF z`zli2fMOXe#}Kbp7*7%Ldua_9L6OPC?JUI>1)U6u_he)S$HiqyLK?&jGRN+z6YBo;t+)ueUc{(5HlY*|pSS zy`1GsX3NKgHf>5gc@{QzezuOi0A)?kh3=`p2ION^X}inCgF?-Zo!Nd=h9YZlu9z7t$g%V(iyv_0Pw71}NuTE-@IUTxE0BQ7M1vU= zQ6X@AVSc-XD3=FVO3zUMOK>zS^#cE5rxj|pkx!0voy-bk$Mm;qTZ*bi=T)|kIF9JlyhFcDH z&*c2yeYGmju;s0P4AJZPWHAZcR$EqQk#WRfkM0ERJwvHO3l(mMkeQ{KdNc17m>{^G zJB)2<8g|&inJ}n>Mj|3s>KStn^?&q43j-Bsb?^o{G(+DfCf*i(fjn-|*#4*uRj`%A3gBX!q}cGqyCyx{Q644O2JQgwP5Oe$n^e#6L0s6!Y_h?j39 zE(_n6B7h2gy_mUakOK_;es;Faf4!6+;J$@d-yI2bSLRYU&3O_OyP^DHzzqLK4^ zM1Olf05I#FrDY49;miK^3n_>K5~ZHEnXb?%t24}5gZ+gp+3RFQjDOW%7{9o<`2O78 zH#N}t>qC+L0UUMz1ub&4`sqRsN*W%|?p9`GwIw08-hx=auS9S6R35)i&T^+M z^jxt=z*=I}tByN;Fr}`(uh`|>4#a!f)y3^sA3K)KYb5g^IOVzpgpWM9G7{8rNv{w2 zUrpl>Sd*odK-3sjs2C!p4j9e2sykk{s(Lx*s(|`Cg*xvqI%&7%{FQhJiF&!38GU62 z2;)iUxel6_i;qShhJGK$6_)0?5fDO7M2S&vz+PFQM1I&Pf;Xk|jt4Uo6|VDENedR! zjH98?&f2I}j$<9jYlDMtJ2~5*iSFgh%=fF(Q@?~YR8g5ax~fLGT7{z;ZU*f|JNJm$ zld&D1?w%uYgC{gjRH|}K4l@p)pfDlms;QekV;^;lu|JlEfr5|vZd^UJ@_Le&@F(I? z!AAqj(P5&o4?A&9*kY)4Au%p`LwYTbL}(!iWJOcKxjWVgbMrWs4UKZW8w}J%VSiHH zJC4?$YlLnGE!c6z6=fONoEMjDUSz zS_>WkJN6#Kk6ev5Il#P5Jm;=VhFVSdPYo#ONDQnAM*-~6?i&*unY=+m{e$^*9~&Rr zgz-QI)sXcn1f&$zf`=hV!4X~ebzr61m0prlaOUwsqIUmQ`gYa zE1o@#BiCIyL0Y#P#weBd)2SnG6Vq5x4PtR;DENu0m3IyDf0`%$(*34JH(DwreFEEQG3Q!#Cq-a>tWPrde< zM-qXlJ_WL7kZq(v4Yj-;#ynDLj9YqX4#n^J<@T8()f*a~|F>02dg#36sH%O{0s zfY2+bNd2!DjQUq3mcgXpo(--sEqGqsW%1@1!8BTxX8(V;TSp`bZ2;i)trrG%i-1~@ zo#VT8@Oh*JGbRKxf!);8Gi|;BLw!Yn)+?g_+l{A$0x@GiZjyv`JCjLZbhPV4j?m=4 zJNgd%c6T*I7CU9tP!(QSB09fhRyX`_Z~misPTZ!n-tRxSep6qoYC7(e;$hcN_g|m72pJ zWA<)uqk6P0X+$6Uq7%Tt=*u}H$`q{ei+XB6z^kD+HgoB?Rk}Ez+f`bUMzIj2oPz4| zcx~x-vIzD={QaIeZiz~@KT9>nGV<~@&CRK4CJhUnTqgRf{kZ$3;Z8}!{Hc`<>KI;1 z(w;=p2{hJKj11RGhGj`jzH~n35GCUvcVU{RS$+UtV%rMBaizMJryFPx$*=P1(o z>ZsjuCgB*_?Y-Kj;PuHm<>v^VWN5L~-d2@D26&A&asWq&BYBP*Ld8f-{pacS!m|C| z&o53PZ{bG1yk0aTjCy8i$V}CmNvHW2x;%e(I6Bq)5-+*>PH0sQtgYcECMs765meSP z%TGlEViZ!@$0H`737MfTqbvm+dkmLpbkA?_|I*z{jsAsZeAMBQdB-muisIetf%1TMZckt# z0J35t-H1S~)nX+jefX>ske~$fHJn>?Yomey2bJuUB-mtB)TURUaNT8S#$gLng#2>9 zkY!-TuBpZ6fz`hAff61bo*h?P^^yP_LmgqknIR)5=Vg>X9WRQPf@$qz%1oE6S1tJt zV0bB>9~Zj@HlMtO2Cb_*M#PXioNXwmW>85*(<#%O3fonZa8uLQDjH90t@!kozS-o# zf0QsEvfc0)bHkuL{_qc6B8za!+k1&NYgZ&WD%1O4z}cO`mRLlvbA-{Npn;2|1qPCb zVBr+uC>Y7NaS+pN)hfWljEQJKJxn2D6}$#aai7%w)=ods5y$l6ipt7(@?lq0fP;9+ zyp>{PK>$je`(r5bu#30ucJsi%0PowY`YS`uV<!HoPrhGpBNUR-W4QhAuZE4m*s`J!VS>Eu^W@WR zX-`Z2#cu;G6C#$U@F(c+9U$K$yRa$dZ)PS60QDkxj1>du3B7k|h=B{aC-l)}nn;HU z2C4+19nIE9uj)mz6@>(rqlhYdHY_MnFs1mTAExLqL=?;Ie+6G~XcY=~JhLRJSvU$N z%KaG6u+QE%2k+UR_cQrr+cgC$O&!!*at>bgguy5R$Vjtum!6$JSzGr^2kXRp(HYnT z7%}{Q)uTQ0clyxlVEL^#JXD8(rW9Ky_(=R61g?ER@Jd;27gXt0=;tc~do&Z8o3K+T zd6grK351sTWr9yv5|l;Y;G|1lNYnDSlhEH3)GaDt;ujc=B_pXU7}+HIxC6}B1p!rK zZ7~sxi@JL6ghHDZ?Q$+hgVxyG9Q#)!{N}0{7%|RR7U;xc%`9|DY<|h^cmPF&x}Ikm z(d#VH{>Y4J6o}0Tbrra)PuBT1xPa7%AC;>VxX?9;S{mK!ie@# zkeIWYvWxY^_5L6&Z#2_4F9Itr&Q86EN-Ui>t$`3f6VnG9Hu*igUc#DWhVf=e;5!s> z2NZFH1AZTnR1vvv5=%QQKs|yA;jTg*WO1w<=nnkK<2eXIBIM_GTRF>B(J*)6D6|x1 z0>zE>;qVHNjdx4;j$9_FfAk4;UnwOVS4(tj8*h#sWS9Lppis>vT$CoF1|c3`<-j=s zk+LF`Mv0(RPQ6cl*a&6YW(m?ku+q+~hCtxj!2a(){ANxasJEeXXwR1KmlP%eB7vCIJ}{25%CTgdZxQ2R zutvIPg9|slQB1~63nm;&I%U<~PJ@o(`2Fm7h-OG*4x2A`S5=aPTfg(fv}rMW!$8>X z;5LEe)&W|7FMgTMzx89AA$6E|o=Ym^!G{v`-^4174lX{zI~ z`xB;DYQ*~EEkg?0g#I-9Ve8Z+s&82+w`r9;qarYvf?hd-p3A%3_%51GrCIC0Rm&eT zYB!Usp;|F)?07x6tYnPH(9q0V)dUwVx7zOD^j&C2XMR_5CLe}w@Ivp-?>HmBmxoY8 zCZ!ZD#Kj7sPKJjGnh5q|{RX|IW(X(wpFWvSWI7@{S^pd`=qKfL{nAf|ey?J*n}nw> z%UP^f%>sV^Kl@I4d%n51=a7XW$5w2w%40@c0Rw6~J12tS_cb*&FMOece}MG}N1P4m zFY*|OPG)i|MeCInygC>cv<7PWuoFoal*$*SyiV(^5Ra@w#J-ODJXPivhT#@89bVDw zGtyB~k?N;b{bq}2r5ROALE4sxNxfE#j=)~tqx(NEfv3un;lBiM8qo0+#g?EvQ$%d* zR(W*c+0CQpH^bI~MVT~LF2}Z;eWIE^9ik)8v|N&2OlxNuk+zVig+ot=p>YvFpb^F8 z5X17ro=#f=pUzs)Q4Kv!gVptg#z%kX?Ix+~?T#(i(K9h67I)|XQU5$sjXcP|SC^st zSRR9X8xv%){5==O|IliSr`v~+`1seFhU9mYAeZG8ybInn%^^`aO=TV}VZ0Zrztsee zWSLj0y*F#cROY6#Lj_SsNPU7;al4ZQV1@Ge?;8!7uZUu{+lDKnvEAcMB->KqQZTA5Q*wow$o)k)pK&1zf2C$+(H1yY zsEaHb((AQkG53%!hQ!W(-DgK}adI}hc*gI(cMz`F@@8>@nDUlwnCrkH!M*Tf;}bI$ z>{IdORBW^rY*Crl@@?mGDOdZG&WA}UnwuIxa38=+&MhLvW4i$sx0+a_K+(NyC>2@2 zI;(~^B5P6H+sJ)SXGH(`tiE9Mg+%JMDqX4CURI%X9Wra*Gxoan0l#ldhXIyEd>A9? z6B*4xW*`F1OEj&@66Jrf=V}=Fed`k4daEdvw?>4oeYM4y!=0_D)+GitA#JkbIfH+- zl)rswL+T!Zu1{wEir9g*8f;a&@*u;nsF>fbJ2zi-=Q^R2S0^?54Uw+gTBC-dpDcpZ zio15ohLfAwo7j8%%cX)03t>?*WTHJb6M>Y%|GS3uyZp2@OqKI{I~cw&oX+&jsuKIl zSt9JbeeYfF`4<&jNU#>ZaTJcWNDbJ?H#yPtqOM+rp70}h8lLq#zFZ8X*s8}zffAX-mE(~ZJt>8+EsLVyWx=v6oPA{c{AeH z_(krrjfY;nMXYx=UnCP;va~v&jMzShz+Z5;=sodbZ^Ob#=aI^C$+pzC_b|U$>1?xX zm@mo5J$|*e<-GP1&=Yixpvt~yeaGE}lp+<~sdJvjaPq(+r~HBdh+&-)jd+clVTL0G zK%a{$!skr@cVPjMN?z;K8{8~e@Npf<=SV3^+Q>|+=edIRX1dNjSAi;Bn=3J>E+r`O zZq5mc!Xg0*S-O$2UE{h#2d3YuJ`nwx&QHm(?H{AGh^X3Lig@URwdC`Ji!z6Lv6@1* zt63u1l3|SB^c`tEraM?5gpd4>M~Ij1?7`{Bx(aM@cd5H3P|N^1*qwkX|x0mvqt)6~(a?1dgkhww);~EY8&+$=`MGEo` zC_Y#@S7L3l{|WhAOjD18`AWk{d#j_H*VB;yZ{2Zv1t_&SMqHD>8=1+!`l&U$mQC5q zFrR9!tRs;M0Lb(lRb}d6vrf5lEZRt52xQ8|ycFWscxBJPJ10{X@jTi|mwjR>QW33B zzAkU0LZV0;;bG;z385bKY)RWkZeO5)ZQHgWD{kLg*=_5RTQAidyYC+x^;uy1-aTz? z>wBATq2R$QCVt7LRT7YQc447L6w?wVOvrZA$1jQx?j!&WI`I#Kf}0iGRhzHJEkU6~ zxNCwjTjz@4DK09Dtf_-v8T;&bDWr#LY_kESl;UlJpV`P8IS#dR3@c~F!bV15MTd5V z!y~l!6ku);y!3PJwK$p7UToj%HRyi_eS+BA+o`&XQMNIsTFR2T6Bho(ec-3zkXE>` z+JW1|OlG_9PAU6gn`;U{9L=Ufmem-9Jm_-90}Y;KdBE~u(C?IvQiQyB`PB(lrCYw|vO z>O$jKes5PcHa6T&Ge?Ft>82OoO$1S0{7Yz=%DyDz2b7Vj-y~26Ho$~?4O`b_#H8lNa?Zs0$WIy-&$!oavDrYQJ_VPL94W)>gqH zDNWlmQT?I9;_&$x`Rtg%s9QZnKs!Mv56L=(koW{)nFMk}N5}X{pS@ZB*IlOC&PEBQ zgM{L6GO7WizV99hXi{NGG8B%6L~Hx*lUnA5{rL@q8Q(37bTPCjs2MUnJ9?>vz-iS) zkbX9}r`zsMZvuvTOiZk;T{cuj$?2K&7X}MG@7NDyd2IJR&rUMwS6(8+l#a8gDd@4}2e@bW8b`f!dnQg);_5 z;?G}JLfXVMT$_?BdIM62Wo;27J^blISQAdjwt*C%qA;RhsK?XZAEfbkC3Y2%5UDbg5|-oSIZByc+4R;U^jz{0Ej)y}a zg+GC5@QSYNjQuFxHbDlYAAl=AN?w(_Zcq&T(G;-Y@D~N2cPGrD`fJKW?{XxnqC5)$ zU2(?huD&9Ev$@fznl&ClwjT!O9-amX-lKBVH%d*|uG-%uj#%0Oqdv+d=0h*JmpLj+ z|DBd91BVc~WlJU4?+yLP_3& zzXVl@8!j;EiQSHxxA6!hL@|YcWNqQQ_*xs++mVR&ee?>UH_zgIc{38keG$|t+@oG% zEq~R3`3M!A=Kbe>pjStbm#sN09Ay35H<-xc`QAd-)`>sHUROo7$;2X#jCXK&g05DKB zWk=O~K7OvQT!brA59rwNXp$o7Uf@f${B~v#y-|ac%KwS>5)QO=U|Km@{M|o0;inHV zXxU5qX6mly;sHD{*K?wm1{=uD(SL@zD+QuO$&&&{?e^?aEUXe}Rhp?~`|-U{i*SIV zNo3Lf?VgwGBcF$1rmLMqd572WtNK;E>sH+a_Kya)zv#!!&>aY%L+G;S8E;4-4K&|I zQ#7@;DUUJ+iP*3MXX_;^)$sVVK}TWKF(~v{jMy7jwhyhZqqXawe(jLUY@{U~(4}nM zuz_*gic5b)q_r|HW5*)g9J3pfW0RR>!K)j1(bAfn1AM5Le?M*K3E3$Bm24-@1vD@g z0XiG?DAHAy-2Pp>t|UPY(*5ZY#kfxn@{~lOyZy2u=#Vkzt^KwRRj+lfQm&X7{>gAm zdIsbt6lgs6_+iKfy-Tc&(H&7RHEoa$*ua1q+AX<|8tUv-WI@k2qBIyCiU>|l(Ld@- z1X`4a5^6Hn3jf6ze7zPTVe=6=7X!YLRsL=SgytlAU`1V;Kvqv$llS{QLe~2&?7osI z;2yKD?~!fq^XI7D=MXSTr~cQ4kGzA>G9j)I7L?#*U=~93lQXz}pMJ1M2*6l&fX7ItlPXzBRv^eI^QpMEmh1g?33tXhk1yoz>7?0>VClRO!~8c94K%} zWg&E7Nx5h5XeFX3f*MKpn=+SP+7jXC#?i&~X!ZFep8ZtWVrrU|+EoQ1H1K(eCg+{7rJxwY#?Ps4J zd8Pns%dX&Jj?O;(B#?e=@#7CC$S}x%f2N7PT}aAPS6FB=uJZt|?}7H2oxSsD966P44 zZl1TTBfbkxgK7%f%@PT79@ndUb5^HLcjeSv(uy?sdZ8J173z^_y%zp$HmO@_bsiP)yiN+QLQ$UqLbcgHW<1QCpdn(vdX(#grBx|7LGry74H)AR-V>LG#@@4#3cgWzC2^CU0pk#cHOl3fk( zV7&Yx%d3$ly{HKkUEB(!PZ&$Ya5{`=tp)<4#e?yU?vAGqj^stXmN2xpyxEoFP>hIo zz-R_QM@h!AfGmM9ptX|4`TOw;?!!82o?5kW|2qJAa}M?k$lMZvb@4iqk&%f3DFjhh zP1`hjtgd?D@Ej1iDf8f9DJwe+`a*+G+3NX}OJKaRIM>zbZ#1U4TUyX+5?r&v7@c=* z8DR`wGNRI8!4T2rP}YYb000hM`y%$^5gk}M*jnV@Hsg{wph;6ygO#?-q0mxMH6iAq z3GsRq;~zoCB(j~Kho(Gh#Cj_7*_v%9FjzL>gp%e@ zAxh}(w)fO}#P1;A*YK|Xk?LoPy^V{H;-pv$H9R24`LWs`uxj``H6y4AfNw#+X^Xf6 z0k}4;+zkKQ0j;b<>R_8+?g|`0Wd2y8xYSCWgP7YBDb6ou! zMxP=1R6(`dVh1>27?v}vCI%;K+n3gOD53%v#1;%hn&SvLg7d5qxrVb?fYDht%O)w8RKP}=KI2R# zd}J2&@-MF5=dMb9^I58#aj1#W7y)QUZ-kBK?9L`YAG{iohgvxh>YvS-=rg=QgWgT4 zmPxXOnG&u8@QqiYWh+I^-%vZhl+mmmg(6%NJH5utZ_-7 zqr(FWQ#L~BT1a1pz%}%)o+DyU>b`4Y%z#s%X=w*I$ADRUKk4{wYlmEa@3jR5S)&*U zpX#K&r&c_7TlD98T+64I^%hQdc=U#!o%YllrQc#iwTCimf^APUR$2ENt;THULtj5- zMVd=-s>Ml>t$h2ah~OAB4_8hWHG^FgPu)WejL4@-&V~txDGkVOASVs3$unmVF#d}p zX2c)>&S>o>FEj$lyuY9q4g%Ro(}sv=E>bjfp5wlYDv%o$CY3s9xj@NNN=n?~gfB{$uXn@?OGb;5@`W6#|Mig>jXA1W%3t{SV?scH{4@Wk{9ETy zFQpSXIf6I~=cPEsd+&;g{I} zE|W4)akf-=MNk!W?a!3A>U>fRH!$u$5kDH+(Hpl_dgy6=IK{LxF~BK5K#|RZ#Ak`b zf_h^1cL%IAS$WFeZ0~NNwa`S!OC47pwlL)YB}&227-KwSSaYY%FQI5Zn?4?W8kG|z ziQ6qm+&XGuiMq!kczQ&Z?&rvX0(3WVXRnA5CYOnpDknpB(09eWj(%!*@CfNh>lZ2^ z>Pm%pQOSsAOvC<|AGxW3B9bb}YzVhgzHyj!1b4{r0VoPIF!4?Uf$B7W=$RXY{m>U# z<}(4-*qb2)km_c8%Y_+dy)0A^R3vl1fruHQ8v35(KarsdRjOzRK2s4&$@J^d+I*!& zmJYTJGv_4qr$!l6veS+>ej03pJu!{|KZm zc6G0On`Cy~e>wFkqwX?68|lGfEciXr7y0z9xyeFb3`hsz9!LlWYjN)Qcx+1l9g?qg zcY?TqX-pk&jN{tn^gV_wxfVENe=M5$8fQrqD7K29MkdJH*;IVwB%@F~9unK(dx|8L zEg-C!*2`PhJlkA5S%;N;1a#d9Hi2)p)_$T4T3cPORl8!FJO?UFc(nax zW7u>G=fa^@wf^^;A;P5P{B@>a3% zQIVmj7xY9)lMo6!1XMw|m^Kawx)nFy)Ggmu-=JLgTq$EWl|0HBP*BkKoT2kwGMiKd z3n*2#6Nn2u8n>-2h~?hxG1i&s7=&`mIbl6D0wBeFl=8oYcOiGrE!`xTh=rIw8y76k+oH`;n8+E?Lc<56l-ndEp&Oy@U0{7!hM~~pN;FkdEPW2t?Nabk&%LYy&N&OX$o=wNPS~5N_%;T zjF3)cI$skZ$rkClg~O=An$8moeI1Av31gVL=FchK7hW=BofGkQQp=$z5;nE=z{XkcE0WF zXl=Y{RvWH5#+HZBPp;C<>7J22Ty}{!;Pxdx^=@CH@RQ_y%I-lI+zper#3_+dyaqq) z9Ids_Jk+mtk->~KDf?;um6HORKrOC$!H<|eQrqfEyE}%-n1w`J8&;Y5LDZ6b>RMFN-J=w1{q zVms>mken(p9V{zX61(5Yi+Kz5$orG78d?YE#zF-i&o1H}r(USpsSaZ0P~((x0yHRz z+>D{_0S=8=L*ab4+=sAz;0sg1C;hGLHp&_`e3F`kV0Tt|X-DcHCuwM{p`?U_042^* zq*f@E=fWPhe=eTJudi~H*PCNcJ!nu`0gF;YFf#EaOE$diYl$6MPdCe}&AESYr4h^? zWLM0);!*t#$xZhr?xv<};6cmLw)45RvxHvTrejY;AzGhrngoGh?@jXZ&BqWbG8QyR zg~+-CRzsS&1nvMW6;hf$!&YG_BPd5=(ric{alBJ}K1^7@>{AUHZA`^q-oNQ&RITE2 z07Wq#BPI7Q?C2WVtYOR)mN7}4t?+rn)Id1SEEBul=zIR zCvtF?dkjphXpjY`C;l-xtAAKgSDsN(EVt|{Cn1&Np((-+L_YISu3-3qV?J*bX-L=u z=J6kfHngBr-4!Zz5GWDl$EZSAN8N)x25#|_Yo<~m@0tkAmZ5YyR@W%mgieSFYOZ@n z&#(;7;4Oti-4b+?ZJKkZi8f0DU3X?8D_nNVdKrs$%kaU+%MA{(g@0e{4G4XIu-V?b z9jKydS3+A`y-{FdTWR;D)j?31zLKfCwBfc`xph!&&QdlSZ80&(c78|=S}|C|#L6+fkcgQ2Y0p4bX(6o8j3dK|+k6fS51kGf^uUgRN?|7^+IZ#VBef8-U@{kWO3b9pMtrqrE$V7WkHPK;*Y0gIPhS z{M}#F6KKX zSBn+T+C)EVMT5ad|E%K2NYCSCg{%PmZs}?hw9^>k>?lA~odUwey^6*ch=R3To=nE+ zZkfghk54KBWbn$mCxHB6`uyqyOl^TE z^r*a)^Dy}S0QAtMvV0q1=o1LUKt(yn&gs-AX0?kF3+^*8cEo^K0TTlB_dwG03d#!V zcAEI2yq{bhg9=YYdCSb!UB<_;Kp})TFW5*iKe#vuVsGjqL^v8r!yQ-<@;r zy+8Mlwby#SnR&nAJ4guUD>C`Dli9B2whS^ERXz>FQ?TzqWvH;zWhXRhC9N+GsAxeg&%J#0wu*Plhc-lv!&Zf2wP!!M^E=Li3! zwF^JOykYK;nQDzlFK9{%3Ay@hPnAETria7Aa$7n(k6C$0VLXpHCmK-ruLtAG)}Dgl z_ct5v3)u+$|0?wLJ{_++1vWcl2dRzGngl*=$@~uh>^=?_@ z81634R~v)Y8Jd%22?g0;sbOer_eurE6xk%lh>B^_xc!bmCd>Xj<9IkgHuBZkh**6f z0pGq5n=#Emf4gN}cjpbZ_2tE4V^jD@R%0*25sI>`(m*piPedQ8s+=$g1pU;qz$Z=K zJE<^_xp~w;tJq1l&D(hmk2BBBhs#t7B5Lk|R^{=%RvInTfz7hibkm}n2D(spm0#|}jvPVBmwJyr31!;VDmG9Vyrg_%ncg69RpaLu zjWOfn=LPo%)5~5MTDr)H*1f4Mph)44Im`XxR^K zxizjDPn8grCsoy9K=9&KIGFY49q`83F-&k^F2RBAt=>njPd1p0DO~a5qO762JMWWj zZNY9PDZLdQpdnvxkjg;k=gH_&b<=z`La(8}un|Ne|5(#m*}P4*+pI+j;6wK$`1S?{ z8W+XY$1^Y+rKg8l7^tmqvlRWV;U-4EjlgUc?y)S_^-Jo!uA_rB|Mero`r&s?rBnH( zl$M4dmlBm5F?NoX4R(K|hB`tf!K}1yC}x6DTDj`ik9ZqY(8|btqW0p=>NYf;!5f1?$Wia=nq2b6~2>pqSs6+Zi@4_qgJU_bwsX(io@ifhleB z>x%$)WT6ZKcSB9wN)vC22Q3}mRr4oFHN`b#lIO1r%V$N`x44G_kA&Yf@@TMHi{$YH zXi1(TY!p@5AWZ7Mt0TPzYttqmKGWK=v*lAvBpA+N^0C-ET%rQsT09$vQQtf_J0D3l zo5#oK5)vKzH?7%>b+9O>FIJ+MS1@fyVcnq1ti!%@SoB+dZ}!+ke!Ck-Sbq%Q)ff}H zP3QlXRJ;WjMFy%8dVh_kV%Rg6-!iDt*j9!uS_v@3UMsEE`Dp33?FGXwdf(Kcq}>eA zV;tKXIGe+rNd{J|F_!FARS>4-c;^c=#cTc0Cpn8zvsM(io@9o4cZ6_QvTw8C?tpAP zO1in+Sl8-v`uLCiT9!?Ht)c^&{J~FmsNMIz5Ys;kUSpNe&S{tdQ|PLKL3|h?)Tc% z!f{Uun>Mbz3?zA1W88s%I-PY9xAhA6o8;g{ML5!w(&M7}XH}3i%(fy#$LmMf`Q-q! zZo!*%L}#p4|8%(PD}bfGU~ws0K;bbCt94$MeUoTD_X^C+D2H@Xh5cwE!kM9oO zBc51BLpm>~JyGrT$?wq`UHB?DPe^KOMA7K`E*$J$e+w0jZi`RE`Wwqn;oAsbkO#6g z3REXzCW?(F8EZRMi!4S*Kd>luhe7b5{k=Ie)IC_)2jED$yY%r##Nm9^FX<8usB}RL;`~uLrI5t z?;Bnu{J>bIRbl~`*A;k^fZi;Wm1lx9n>Nc*O ztfA3cMwedGg)h;@s$FybPxf2R)3|QBZ~UV?%OsD-FB(c;%DyCI>^?$%f${6AEb&T7 z)_{{t`C&x*5s^e=$DN(LX8=^w@IPw1jw7cxN%$c;3{$UxFsH$KokKFhNaOGQs=PFf zllboMtC#tO7m%%SIC$#eoR`;@_5(ynXMAUHD!f92FbXQ9hm#J!KWd+UFCCPP2Rcfoq8UzjpoXfn z-Z;zEh`8FwLJ!1ANw*4w8ZYGbRYN5ieP8R$P2MZRA?{XPa3?{F_ud-P99}PiUAEgj zboBpy`62K|ikS5CSe}!(qk_JX8>WR*l(-f4iJ@0}=(;7t@uoFk_)~RU_wh|p6&dU| zM5Xd9yc0?RH*K>%U!dY$(^kc;39>9O%cJ7#m#9q>;CzSLD2H}7pdaQI3To$qVwQy1Mzs#(c}oPN|lPml@) zSW9kvTWs~`h_4hOSMz)7S-zusVE3i9Hu*7*0pxfQtP0~mPFH2N$?g>%*O*WedL~-} zZ6X$r*F67s%Z6)8sxR?6Oji@Dxl(H3L=sX`iHYE+1LRzGSw}upxEgLwVA*mvx0rFP zO`JM56bO}sfd(%@t7LR@T^~S zEvS;Ae!fq@Xw7S|c%e;f1)OY1*2jn2u*0m^m`?xh!Tim0N|K1jdTEq70+9QeNr}MF z(vZ_CnXa%6ubiU(U0mOenKuZjKZgJ7kcjbxaBIP)quj-YTb7kB6KyB2?H^K&B&SI- zKAT-$V?wWa7axP6YT?}vAn^RK(>H&HeIG!frz&e{p4NM`VhcT_^ZOmuJ1{w)I5~j}aSG^kqKWL~z+KdiVI7?{BG%V^O zG0v(Rb2FP?!(AmL%SXjTotrw7Zcfs8+#N&KQl@p1ur~I**Z!(~xlM?39PC9)G*;bl z3-P_Mvkxa~B!M~io@o`8Fw>pdPAeS-z^2XT;Si7?UZ@)Qd$;Kuv6WQc?yGD7VOiNE z*Dqr51Q?!r&YjO@ zxL2(Aa403Y?;VFnrNgl`fM4-Q6j1$LvN65`tG=O{QkW@aRIEXvjuA1BQ)da7!U8#K zA`Pa!npnC&Lf&l&WFuuHR@y@x?K_VdEFOme&b_ziyGhI5bSG6pi!8_|vh&GLk!wj9 z;0#D)EEWqI138b>vxQ>+RqYdumn>VuTiF%_>^_V4aM$n6K|rl%Zw7%+^T28zvN7^= z>{^7L;ONrsyq4$fWlxsZCs}lAJ3m)p0mM!fNod9Bf-p|$v#I@TZaRbDC)3wa;4OW1>L2`90(-3PN|4nzg5wR>%#xqrOw z?|q&FV%g=C?Et(Iy@G6tvpv|15z_e==Ud0U$zSREdmL^hq%uqxwp5L1lv7%(s)Lk^ zRJbLHH=-2<&QS#OOQb{8Q>ZUuALj$clP zQ7Ia3_}HEi+w{rkO1lTmMthJn)H{3cVqhDWV{Ne+xi=2eIM0QAPR%ZtPkD<`S2)bA z|4vPny`(E4kUVUNZfWoELyinD;f8Uz=4G{y_$D+5zqzO}v)!dMjEf5tJg+^D>sD$vGBOyjAg<=Y~)`mxvuA(hGz%HL599p0TO@Z|qFeyP=aN zvdOIBdr0NHAqY{V@`0)t_b%Y zm1TG~#99G(W^HU)yNIXd5j1&hiyP3uKC5X|tnduH{2H0|a5`Rjxo{4D?&BdWtBrE{ zgX8?6YC*h))2yhF2gt)s*?X`HpVchDeeYb0t<20L6AinC(TSEfK)Bv{>#|p1a_=R6Z z31^eR+A?UazUbjko| zPS>`@3q)PC&F&4sOE)jrB6R!z#{M}J4GYe_v&Wd^XLpD*?USN%tYtU_p&0QK9Y*F= z<4&+-=|~2EAtp#)iP`6xC_i311a6L+BT{N9pQtMAzV{rSajhH~&0~()U7W zUfhAF#Se*+%Brh&!Y&xqkWvNDWyJ4&5b^W9Jhy^I1M3LO_t;T8$cW}K+r}lX_~c*u z(GPbCl#-5ShdA0v>?ZoqMz)XGLXX>#8TN|yswn--BE;F80m7-Ny_=mj?TV;450&-) z&_EQHi|y6#TCybA3|yCtAHuP01UJlnSs>N{y_Ev^S_dUA=1_0Ou(RjS()TS2nO`=E zlk$P{Y*NqX4pZ}=c}4_{`rMyK*sWG)8{Lo9_8FKV$ha+)FI@iZB%C77+o-R-X~)qZ z=x5cujIto1-ZL_-_nzdnbThyjdR{`jAG|BHIM8j~B_$P>#up}w38cewU1vNj1qwwC zJUA$pkS~)|tSCrTGCBVO!LbzR#$M4hbq53oWfl5muYPGB(|cCz{xmRAy*n*(-6 zCplv7CLuJPZVA9;)#fWnCdIA!Liy(mS2?-LRAqWwdj$QY_=c}fLy1YLnI+96I`8w8 zFKE(^iILT63*XhqvJu*X9Xn`WPoLS`0ws&k{=k#ve96mZbcW5DWG9^|z_R>uyz!;H zD~>!nBBK-fB!)iY3OR3eF(`N z_ugIf_hVQU^<8Tew)2@ZM(RX0V%iwL=HbTJDX830i?1I`p+?GCl1-m+7v#;7tQcg~Z`PRr=bCj#>KvyK; zR@Vt*tI**%OXd++Vm{XMo>DwxcE0mHWd|(r0edeB8AZXIElmwxQg2C7Rrg9Ki5d3- zk;LbQlIGKiF^o7{8YTb%CnL2=$Y6UF)?$I%JM)sI*ywSHPU!6yr~67gi3oQOD23P$73Q7$uxNy5v9iJB90?2*mgcW|D@yRX3$R=APZqO@7l>FMgKKF#_3M zpi%1QF}FN{fx&yNk(~q)pBJ9&6{S|c5SLTrxmIKp#+AUSKY;NfTw;E8Nt?+O=D_zd zqtFG2mQPX1(N+MqgxO4MkI>AJeb?IncZjZ=FWAk`tt`YgC4tJcdbo*LREHMs@ittm zpm!9=x6js~#!g&6xrGDHmgl$cQ?-SReWJe9Y(QfS<2L z?0$>nqQ9>5cnJpSs_;i}N~uQrL*4o?)B3aRh&&766>~~}H}Pkkoy}%-;x$%#p1Y6^ z!}qK|2~#+8a^hGoqiM&>hi?A(`}d+SkBg3`317oRKuK_!_}IJCX_ry>zLQ$uI&-hv zeH=?>aF4zwZ=?g>v{$A$Gk9i8ATtS2XHT-pVQtK*4$aZ1Rzw#6KqZ`y3?Q>fo4DW~ zRXN#UItJ>+SG6*yAJQp*1&m&MUmWKY1x0m^WGu2uA2CCmk&+OS&0OE{w1uzG!$l+` zUjcW*F#A6}OP|kx22OdY3I_d771WrDC41fA(wrbigD3Y-9dKtyw0Gyr8CHY2wlrRd z0uO5@mb)j59UvkRp^omR7-iK|X1xs!z&QfA8jd`FS_qWK8xx@MjO!~lOl}wp)8qPQ zo(0)Dp_uSPx%`v-MQ$_8W$uI`Af+TJ1<beaZ3Yi6fAw~A97G}P1{ z$`VFTwQhmN#!-1h@^mxPacE1WGf4>E&>#IwkPe*maz7YLXpR2ZA8# zB72KT_%%H$R{VHWRF2=l?*utt1nj_0TDLYsE@gUS$eD8AJMY#66eFL;-T}Yg-mTte zMusSgqG-H3D8&A`Dy-D_Dwvph7uxPI>t8s2LYgS_G7^lMb6-l0f?B#=V^{~RFaU%y za$*lOBx<@?H z7S_~qCN@$;?oc$sNxlmROM$zGGQOvr>n{4FY)nMzn)ul|FdY48vM(Wzcsf8OcQZt* z-B*t6cEZFRSUag-8>u}CE25V#oHG6WG+A#9?yc%8({P?&T`L^3n=z>C5qg{nm!Aht zi_aBb+bV^xqf;|#P>~fNX90#WDCTh_jvCPHgg1Y)r3Hl8LpEW1LE>x z#U;#qnVZrYP{eeUm!gv0a#65!N!E$=O&k|v&jigoIhYD>s@Rf!(EUg?%$Yn^v^6Hp zv{Gvk+oL$g3#3Hjf{xKf{bcvOgbkP}w1_QdvRIkDU7#WS)K9F&5-&ATu3$5=C9ri$ zv2eGvmaN?pn#_R1L5qsOeormfurDr-s%E$Z1Rcg%Yl_2s1(fC+e*`640u+O&jx(gI zeP=Z1fx;6Ze{$`)?{FBVtK7E>m(kY7d-q!NKJODUqn)Y}H}clgY_?jyeMEO+Hn zsW~X60zfe&6~P}m#!%$=XDIZXdL3hCTplVUeAe)zS~UPnN&%J%iC#-YpdsoSrhNaH z9eVrMZGOHqeyM*UBq6FAp?Ycxj}}XB!5mS*&7P3swNhb1n3zLJ4HU$6UUN8!n^N+3 zJQ$p>s_*9$UyY2&1ikliM&}!C?@kuQO-!~2guc9 z5wNKUD6YxR7%U-v>Q%kV$^T{@qFHyqh9vybh-ux zm3Ra=2i~7W7K_sKhsvt{v?@J6w=)o%6CQWTOO=1B(>#jBop2;7ZG{BzeQuq?2%p8{ zX0N?g*f^Q~ytPDRQ?EyS@;hlBKaowlFSHt=?DchCd^q!-5pL*u)nXK9shgh?B-Iqe zKoam}3!9XJz&pYguM)v2)+*M|nsuELvib+qU2C6l5>i&h{5H9>o2FsK@-PS^mS>b( zerEHVB2|qDMmb#Q&smAkYz(;1Ss&cPKGqV(rB*nV^c=6}hRA256?fP-w8-zUo zhCN{5UbvYlL(#tdZ(@K9SMjEk5fACq2WNI}ZmzO$4WKngUM^&2Gn( zY2C!+<~UjzsU%g;@BPz-{sSUtnm-w0UA&k3yq9A9pFC;$b5>t|?exgnd5(2Xi4*F# zBGSqoy8PsI-jfg#sbSz%ti;BHW~yoZ#nX#<3^sh+(!pJ)5ctl7A8uVT5o-mUiAKUw z?bU{{WivVu2Aj2DHd8@i44kUW9FWlIj_Xkh$~fXl#+=EfrGDjf#9t~ zGZ5-~O~Y!2QEF7#dnNoAeK?FBc5goH9JL@8;OHl{XWz>-vrJ5k=coJg@mAMkm&I^& ziXWeiAV69|nIzk2zdn{oCGYWk+9a4pk1y3@77`MY>Cgj@M934b-{DnbF-|P>bU=Z_ zq%Gm=>ziAF7Wnr1%wg^ou4tS z*++s?&2<;R$*^L`udva*pvA$tP4L}A4M(B146Dka5r6l1q_ty?jHzDH+wy>Kf*(I~ zvjNDtzxzi)LrYSrk$AH$zuhytHNHW{Li#ES;w9j`WdgJ+B6)tgT81gwH;+dgkvX0z zx3-BJ_U*J6pZ!hjMX3z*o|gkwiKDfbkxU**Pvc+sE|Xg|S6ZzUv} zjoX?I$hR%NtUIh6&YB`5Er4ceH-o}%FbvG*zWBH%^Bc>%uX5iA$T(grf-d1v-6TWW zfvn!oCxAkL1}?&>1RoXbrA0woBt&v?F*QCuKA5GY<;I%#`R?7aJ!*YTyM@*5*=h!e z&k3-2dALk?HmEU%uCo~53qln-VC%gewf9RZt89%-OiavlBO)SNabNdcaa*=sityY? zkp9GOuCQk9Oc=KQvd6vRbzA|4gwGM~ecqAw6Zm=X%W^z}TghO*P&VlYzq_5O4jmQn zdTfx+Zh-Vz5>hqG?@3BX=>OWnPymBo8qGFEa-fyX1_bV3zIpYj)^qhNUAEWL&yLt$TtuIr?C&HcUw} z037njH7?uunxX5M(Q|8X!n(D>)9Z;wyTnKI!TQ41OUl&}i5S1PQdtq~{v>p?0ntAV zG8^@}sDu5i(@O2Ej(wt8E_oL2E@Us0rN%U^JCm0E8v#q@HV2J;noR3(Nh&EG0Z-E( zPJ~Pot7FkKxVDq!gCou_r{a%+vaXQH1F%-FEiC-o8_l3&VcFjdBPnid{5HSX7?Yf6 zI&~@(hD^}!d%rpmjmOT1d^rNLCz96#>44V8My{zt4lrnF=$C8ZcXly2yFZWSU?59E zZ3f0iGq|TGCc6AVFi7vzX~8(WRXfbQUHU8A`1WY_Ww`T2UY`ftWpz@TWK<6Tv9pnH zD(#qNN1+8)`Rp7w#WVJv{xCdRvsI9;kO7mOb(zcSxG69Pr_uO^BYIj%O-+$5gSpM-7 zyAM}OlwMQ^*Rz-j#yf5V$&Fd^>-1RPPYk2IdSb;ldxRr z+c#(VnMS%_!AJV9pLhy+;*~I>a7ZLgR>e2qc4xw=^z~Y02WS0U7yQ7frpJC4i1isCF`mh!)^$Dzems- z@7CYHBXRWs4>E`7$pYy*uUjh^q)%wH?-zejJukXp9SOt!_&%#DEBm7b=Dgkf0_SPj zj^%HDK5IK%ZR7r+!c0j?0V4!nE(v{aCfnbhj`h~|U-LeEXv(4ed=CbY`+TpXwqH=9 zjG7%1v!A#jDjl1&#YZVd?T}y5fBGXYS_bmXHSOiX#K4l9;KQiMFVfSw*FN}DIHx(`L zt0HfR0(HSKC{`WX>WiXdVlvwuN&(6>YXTD}q#@!JsCoB(n0P!L{(5}7@2qMXG-V@n zol)@tLD4v`6#cHE>CG7b`N6Ay#zmXuWWLDSV2Mh>Cl1Sa{q;Hv)DMC5_4R#7c`J&A z&7>bmPuTNn2PBTZAym5T)}%NHza9qtsdDaC@R#b?Q0x?*j0-Lec%W`0)O#lHq}<+$ zXRQUUbNt+K21>ip&Un9LzRswBx1NjhtM3t=oj!sK3jNV4cmldw)}y4C%~0*>Xxaj` z>O$<19v^s$4DH~$zB%gK3uX~A(dRczH+e#MF-qF+6?+%kzv<+uuLC1m?3jZx>}y}% z8*6fH0p_GS?+6t0P6r@0eGQ7r=P%OFQzW= zdi%2e{z@V;){>l@d@&`@;_9UbE61AK%l8ipn$AyaLO7kv^JwY$X z%Cd9RhaeOJ4sMMwm)CrgPT3Ca@u4X`&97mXEO04q6^TPAf*lo#d-GEw2&IF@(y-ia za^L?6sc95KhzDPH%Pa_jm#i<2NrRZM-wsi@-nBlT&FEvL7PrTv*ljhS4>>w3O^ik0 z^&||bux>~!g*ua~>nQ(?;LJQg=NHN>K~&zyH}_Bn?mU&%eq}3Adp_=_X*Jnpp+v!v z@$6?hKg?G7L5ny#I*z%;#Khpk^eokwNK@ugV!&sy=g&+|iptB&uQ}V<*zBCtjqibw zrKr04^RKnW(|;zX3pGKA%+3BFnK;gICT0GR*k^#mmr)L{uqX6 zf>pr5QT4vkDD}1_8(Z4-ahPj5xE6&LROIKymC4t|epl@dn8`JMLjEaL<<3>@x+*=x z51;ut8j88oS{a>b*ll!jnqoVLU9^dLWyG)?-sbsgz zC+&+h4WXu_)0m6}uQvZsh*+UE40+A7nH%ExTyY)<1yXok>R6`L#@J3m7sX)VNBlJ> zT!%!0HI>rstm8U3Ci)k2W{}JA5p0mWY=AoPGS*+H@7KIp+T730mm6()m-T#aXMy&s zAqLMlvrxrk#$n^ZpTJ6@@is8$5l zt8J4}G+tq{t&{O^fqyVt7o9+J3w78N!SCB~krrcdvOwf9z34qY%bHWVJ?gt9^nyw> zl(5!L6ASW}f?XjTwq6O~M+gevJcDnvf-%G0lxHkcXmWhmJ|i`Q7&W!(%)!r;cR)O> zFpX`Xb8>|!Ri#fc-U50f3RO$nQHFHvJFsa9c%3K>-k;{3r7%GeBOAz>?~lgAT+pz# zW&oW$U(<>cB7;WdjCgKJ;vl7X7>e0YG9AbwmX?>(`Q4f2)0mO#GgwVvKq2)yWI+r9 zB4W$aQJM4ES4l}pL%Sc4c?+TuuJJ>!Q^+hwDVc-I3j19^#h_i{+VcZWfPQ%VgBHtmU z9=G$Jf?(ucH!O+i*-A_6SxG^xad#jzqh4$B-kv!Cik3z}o?8Hwz6NXNnxF?~@Cc%|h2tPHU%F6D=Ij zA+LaZRj*pkf37Yd?=*wU_TxngIYN4A<3Bm0KDGj%VMJVJU}t&# z&8_L|`c3%*gpBYy+EJeU5#jU`%WwG4H*D&D2VJKU!7^@&MxoMJ;b?7I-d&Q5_3$VD zv|87>D^6B7Dl(-OKczD;yKl3f^w|e(6zng;;^LZgzwuCo4C?HyS5SuU3Z)^yn3etA z=>?%ankZP+DfxOPc!DK+BBBIf)z~%?rF%ZcLnc23f3e1-j1v2d5r|VLImG-cTrQOO ztDaq>-lr|$V8tY_U z{d8~^85S1FfG|u5jB$0=O$n13r!3uV5E5`# zmoo`^QY!jW-Z29M1CY+=YGs)5C4+1CWPe)iLk7mKoB2B&X+N&REM-(OK-09xq(s9( z=mh1#{J&{WcMTqDIiz{TGkn5dSFzBFVfBkT2goTW&EbJjjz=TPtGz7(87jwdz)k&?XUu=B4 zjK{qLH)(G3tLwX>ZdzKXVwsR&CBY+ZuH*!0`uO8b2po(ldyaH5)QSC*boUFr9eVbO z6~PDxCSwBuRcYxkeZR{-+z;e7besP^U3>|;DMIJwzWIU9ss?06e;!Be+5BD}GPMi| z2nak+8|J~dH#yd8zEx=VEn4J^mTT4V+|GQ(`)nxE1rNGfL5Er6v@2Jbtn2r5BPf5G5< z^)yFaQ|5t;boeS2S~Hd44BcO5W3)FE3x|C3k4dS9Sf_kL=0820wYK{5E~jl+V0iI* z@>!E6TikdA{)XQMEMz-WGR#+@bRzEaS}3AFQ|9yW8X^5uVHxO@vQ{Ichp zR5y4kN1_owe-jHcnlMO1T~HhR1-c13w#PjKZ?Z5CX?a);sbLizj?twKq`erKIig+Q zX$;>eE{C`6-#flhCrygmyPvOB&?qnKz>}4fmlu|lgo7esx6>u;^pc-)MF+EGxMFai zpRNAYRqGTxb_9exmC)dDIiW^8KFV2=J zLu3ACyD_I=3zqQRNnoh2%3vN-m((*q@*iR{BgbL@R$-01w)H+UVrA2EWtK%DIND|m zQ_uE*oX5MFM5q|T;6Efh2Jy{!u_@`|ZloxA9xF)#>9{c;#!sxv9A>uPI-6sN+T4}z zH3RkJ37_H^epxvrppsMjLmBouix3JI79{Bl!olxnSdyx2;ty!1?(oo*tYA^>Lm|ye zym}e~JQ25eYMGP-AjyG~^c#!t%@uryV)vYTeM=39P#3S;p>T|kby&sVH1LO(ITQ=G zZF4=6DC95K994_jB~~iQ(q5ZR!h|oZZ|7BSAJG^H$xHkTqw2FjdRMM5`B!hg+Ihj_ z2%n&Yk*;7qyrvLFV;A-H$6!5rlU#$NTSqcr^8OX*rOPyJ%=SDZa zCH{llAe2ebRL0YKP#H%C_SRsmMYehd=ph#k#G*^2q|5b(&=L`C^;c7myg~n7&c^Vx zOgocMxn_JFGCA2bi5>mp^yqkb@nH_djeGvk?^?D>!3)!DFGRAo_OGesi@FI8JeV-h-AM+CX7wZ_-YYt;t{yQ?Fya1DbXN0JdPisDd#m7 zYpCA|xniGMt5jd??0;KZ(`EC}1MfGHSpktyDtA(AiVV3>nu3f7amFR`Ngrb8sDnX)f(bL}f#W3hbr!d69RO0xLtO{MtX z6izSL<_X!IjXwZ=9^qC_e(Aim_jYJ~hKZ$|?@cxl$n#ZVGjqQBU z-1@`{Jw$qiB1LAy)cC0#L5z%{ESb^lJ_x&#k~by4^F6jctylajNY%)px-KFic|vW9 zpSVB8p;n@c3`SQ^g>JO7G&}yCbz-wPc&3qersePx%6A~;>txeJEQm?Lb}yL*P|KsNzvH%4J*vUnCNLJ;_1gG@r%CvCuk{J z892`4^0tPH;>olrr`;S9%bf!v}Q)hpj`L)4~^+t~lW zr#t*wNW=Zm6fe^eEaLGOV?83@4~I1LGgR&93J+AD4rj7IzY%dxvR z$6|e1>5~HCJTJPKh}eO_Ru2Z2DVtg>Q4Aq}WU;ID;&tb>LphY|U+QYtWf)b#C)Mm) z+SApzeAd6Z7JcAlUV|3JNmiu_69La@?*0|Gwl=`CH>9_v>HQv#n}9{lHF88Xrdk|r z-aB63+4^7bbaiDiNcN_D(O})rmqTWTP_Yw=vKEyQ`1FL>J(HyQNk*c(3X*YCqVFv6 zN%_Oh*ned!sg<%vc=t0gY1=@tUpmKkjQ7W!cRbo0Az!aF%$nPi#U#)Qnt^~?@3WRL zYzE+)4;#%3U1@oFG(%-G`Myzj=i6-+$m@Ou=l%7OOx;3gp;B=z36B+}2bXcocp5*t zEE=Lj>4C(Km|ui*pMe(h8jExhg{iu}T)|}I9{fhxp1|MZ^lLFui0}|)L^XFSB(4yV z+QTmL_;)jW3)Snhsz5HPVq=ydNkzeK0+3@w^YsLu@8?rOlHsj%@~`P+?Nh9r=CLfz z6J^v(p7;``jnhspa(Vnklk;N7Eb&+Js4RKPdaWCt_Hc?nnhN<{Vzf;XR5eFG;&;Vz z0#RvpetZJMka19V&Xb9jog1;e(8C-pTH9AZKqlLy!6?|Ej1Stbn&nLEibAp<@ACw@1^?f#eo zkmChBHv!L@&&P6Ke<|*^9#kSM zl}=T4j0*h2Lq+^^UWQb8M2H9gG_VlX3t@9ORzUu$BJy-N9J?I@fuWzZnd_lMu7(ns z(YZx6i9ouUjXqQg+C7G|D-NsbwgYz3`0eLhdBJW3cYLF%`+5Kep}wT|@^fJnlUzAQ zWTIqpG#%L@&7#@a5O^Bo7)n^N`%g8C5X)$_O%ks@Tk$ zi0QmN$fpL120F$!&**~qq{5YQs1}PRYA~E5JyC25a;gwT9uO6s5nLHh6ydM0`u@vS zoS?#6+cL$LWAO`*cP*Ara+fx=QxN5Jc5Z=1V&vbb13~fvez(nBk|kW9pN5~ygCH>3 z>$l;MnOY3@Ud49U3U z77!v<<1u6r%2cuLN0psSVHoJDXI99xCa%MIRM#PJF?4ApJ(Rb^!dYY5dy&1r?~7CQ zNCia980Cv#l(%vTnrbFu_OMDF{@5fab;{w80X&;*NHz)?G|T|2fAM6xZi{92R4-^ucy}dl@g0id8B*OZ_@E*r=6#^GskODUo;sIlgpb+lkH6MS;>j_{NtHBCb z&CtGW3%^k)--Fh+DG5(z5rZ~*Q2h-Cpt-u@L7iYM_97j2}3^I4Fp_O6z=)1OQiR=mb|+*O}Q_R-1+Df7ZNce6(Ox2{NBe z|Djn~TceAC)UxZhdKrg0E;cr+L<4ViOWQ;C>A#M;T=eUZPwbg zs>*=iqju0tIFZ|@+1c6Tw6r>t0Tj?%+(d+F!(zz~d#eydBME$2Hz;Qa9(ZZ{%|rhN z;$DFde92dPq@8kGMH@bz3Epm_?eU$-c-~$lINfgHpMpeR7rp%Bz|`dInkR7}fOT6= zbSTp~G7Lnar~Wh?6V*J!#+pn1I@5*}fh?A|IxY4bD_GBDo$qUe`Hd^UmY2g^yPAGE z7gia*cBGrGDWMM~A4~>;5h~S;3{4Z>eNMA0OJ~k4UWRa>I{{^Zl%Fz!8nH&lkQ1RK zts2v`L!ur*RS|-L?%$1E!eI(EJC|fDT1)oN0Tn@YL#C6cxM1_))C`Q{ zr8*7*^U6Ph0=v1{)^(v@1^BI8B9%{sF_Z7K+3rT2DHDCH!hm4dLvra;mcy3mvx#W% z0jL4zqD2bSe?gV)4=ibDNU8EYwN}XD<8%@R_2hh1cpbO<9p|(xYRpIRK~>ztd7vuC zjvZ9f9TR?k$wX-{E)FGmy9hI7!#n%)Y}bXHwBos+m9USU`lR2$$lxF#;{GD&eYexp z`N||7igf4%>_E;wC~D)ZW6MnIVi z#G0Kf)DU|APf1q+6;;h+9IPqIf)yPk~}14-gw803<8Ct4o1ad23L&tGWF9l=ohtqGFv9xJoFe+2c$ z3s`qXFzf2-I{h~LZ~*KcuI)7X82iOHm&M0h6Os1Qm6$`|t~R%}YEXy0Xg(77K7LeG z#1aYAITi1!!je}z7#%HVk?y}M`@afVtWTEnfT?6>USKlFsjW$>X0S|F49rX}On;}A zA1k?y&q;ZQmmg=*U2wRch60L9Ngv0>A@W}m=YOfZ6#TZN&Qh&6aZIn4TboDrtzzr-wc4LTegJmZ}>-TPBQPUG!v0_w@`Oq(@>M}o|$tx)X$DL1^2eJY%=4Bn@0 zN-VIFAW}#Gm0s|&9{L8DU;mZfcpVdy!6tufur8Ii{B`--33!s4{+`XJjtG%5!zxCW zl04_U(e%2mo}SB5zvx<$zJ&$Hi^@0Ym6dVepfoOupgO@uh?9%Xy6KQ60k=Yl$If%W z+UFD%4dh}^wA(m3t^sqx%E^R@b^kXJv4~axl3TkWp45VA7T_Yt(!Pt-200dtW+Q8Q z3j9%I68jkT_Vz|D-CPXj1F$VH5%fSY<^Ad8gR^%hWBS-UHfV6##OTflR+{DMYVr4 zP^;hgcRg-Xc4E`?;?bx=UfmUQWu859m%U=U;)G-6hSkZXcmyrlY0K?m#JsZA@~Qpq zjmgvE+>`{AUxKsVy+WA{%e`I8(R?zmDOuD;mwjJO`fu<-kIkHa)Y{U#Z|~LuO%gBf zDCtLM>0^Y;(TW$<&RslQ6sLh8H$umoqd_$zBp}h$oVy+=et%dK3KN;3=&Pg5G-`gz znq=V@iqvYs7?v>}-OMKDR*B)!{GpjD1Jqol$UBA1YkNLxaBxns z4f%ot2K+pqUN-~1t=inq^sSi~8#@@1CyRQ*dEN=3l*2xKayNeVjE0Mg3mr&cx8qb^ ztq4HfkUW`Wko`0|hs?N*s3VIW%4kWG^QeEL=1rA`q`6VgnLKYDG1x48~P9BixerkRSnnxbv3RsesY3 zE=n4;NQRu7IV~t3*u0(Q_G9pSpv#mEl#P~=1|-jn=AfIuNpFwHzG-CJ*xH(d+%@Ce z$&5NFhO7?$v?HaysH|Z0q)5JFk4)^gJRB!rJHHr&1`-_`xzBs09xF_1(W(#30P&6j|3eyU0-y=-^@!ogl|hsDfIyNC-CRel zG4rP)1E`(eVLM7vY6k>m7*olt+Xpxh%HeRoiy6ix@!v{Xr?(vw2DM-B;8SwGKEHU@ zPpNAezq?zASZb1s5uY|}xf^tz>*NWBKks8ax&0A9BiibtSP{jeDLOWsXnY^nE+iDs+gVfbYVz|}KTY?C{69@^%Vgp=6 z?tO=kq8c0v6dX!8n;P()NALT=QAs@NF3S0xTBHC8moGevC#6eE0x6^~Ra%--qeYvv z2Lf${-iO^hHH#sPVn=-sZS3uF1BTMy)ccTY8yI|@7^4G{Fi<~MfWu)&&qYf(ffz%@ z-oEe-`>ka#e>)Us9{AL-{e*#=6n$Kx{V7SO*-0*hJjrg9jpywGNQrC%Gxu9}7vJvb z|KyB~57;$DjKhcbQYAGAWI_p{Te)Vv5kvcbJd8SYFDpy$dlh|}&r=jjcS#~F^U|Z-aVHF z?pG2Xa!HgPe$>bXm<}me;(!!cz*cD>*Ytu^z1g1un~)gry8_#-$)_ZLO=84X*TKas1L;SEzsWy2)9Q?Rka4VB~C8UBPT5) zC6$1Szp#+R$--Y#>VgyGqwl*VBO4W@({3wi0HdxIG6Hl0_MP}cjJ!Vk?`SMEKCZ+a z!c(HUD10vdmufC*{!!3cmhN<5RNn`57p?|28@ zk$j6lAe!!1%}^2ulp;BB8QuQ;SSGrVvFuXjrJBELFC=`%i|5wG{aH6Z6?=JI;}M>2 zMSegCO|B7NZ(bj^u?8{6z7N&(%>cY1?{6nw6_Igfw&Wh`(tSuISnc1TkDyHlw_ zYCO2_Z;bJ^&S)}qPT|(fd9o&PyZf$G2%%_``nNnrv{v!m6|`M`&#){AEN~p~@2b3T0xCXm zLw^C4OpF@$1<1brAak5}fXh*SWk6|;yJy$}tfW1ME4_d;TaMMyFatFevcJf<_8;{8 zu8juc3s>_uQad|45{F$J$unaH7gjAwDVH+I)6O+7KVFOP)$%D>7eFEw)ex?CtCShy zAi}&U)P?jI$>AeAvD*?TOGj_t)hh z*U>eZ%g~bKT5dP`;n3yJfe?lUhF*~oy#b4`B|h4&LUjAykQK0lf+}~dsk@a-x^Jgy zUISpQM%0P`wqFLU&1v}cIb4ztCsvJnvfA0gRBZ2fW8`8a^*Sh4*kxRQ1);!|d;9k7 z)#ZLP(nr^C@6H_jnj-aGQ>|0qdthh)D1C7d3H4@B_-q^e=Hszx&Tkp+5jkEDt!OG1v@%7H`fdl<47OSivomXMfg3) zb{^OkEz1pokDj`wv8=4DZZRu6OpFOTm* z&2lsyLaMTbm9hxC*cxwC!M-KuNI!FyTEKApYNI&4O-QzVHnd0N*GhHjiwPMa45dlx zkV)22k*`2qu$J6b#QX%hz}EX9S)u8?k_c@&HLNqu^D{mdq|SR!tQEPFA?{eZU6qBw zj6)4#Rsy%n;cD@oNkOHt9DCH~s39BJTS6Zyxltc(ZeIFMlEF&`;x)HuyMTZ%@&Z{@ zSa`N)>rf<*Dw;($26BEuTI$Un834l}o&xx0b?Qh7(jM^Nyi;SIMm31Uty zs{goRo~8g=7-Julj9<|FFxtYamiYKSk7Z^=3>gCaQXGvxjrFv&njzqY2cL4T>549! zzygR{*Sf)ysd}E5ng`z@rX1VIN2r{`hzJR*Z?3NlYd!9>`0Qg2N?qN1_^NN{Y zuXJ91KIFX^O#9lw0S)tr>4k&PH7anv?~b+E~R%VbNAwoHmDlQL+I*36K{Dnm5OqQ6~v%N~t;k(QmjRM{sh7 zhllHg05$VI?%Ov8;KJ+%MnJ|Vf1ogJMa6c^{vX$G?#}poJlmu6BOdjx*IxfFCYvWd z`2D!4X=|Ukld)ryHOmcd*?G`2i&uYcH5X`-r7-pQH))HriCBcm>KBXYxmvhvQs0zA z^8FKd<><*KSJ_-|96qBXbBXNlUAW;!eXRh+!Qoag9P`^Rz4$F!{LFCQNneQ3=F0xy zRG^-=@*Qz*#8$nf9&)8Jae4FiF!Qi|U`6md)v+TtCeO*zgCDh?RPo>K`{?ZY-er8a z!#K30X(E8Vvf!%SByxbE8yI&%5hMOdoTWGLsk*v4YE!?FFqVMrtC%x8c*hscmm;$P z)2MIqUZgYFYrC}byp`p;i5{{}iW76&dsxZ^aL@2eeUim09(oiK`3n!h3)t z3&1yYtp`A`mVrS|dR9fnqlGjK;9f{f{kv_Q1YKW%CWimYMrg|cMk2%m)oI~A#Qbz={s-hw;2qt0(G-3e%i4D27 zTM`+=@J7Xe*2Y9}sxJvMEY=OC4)Wfh^o<0d&C&}C@9&#Q{XHI`hq>`4sD%Lj4L)aLQIatSjGXZo~RJ}{Jw zgF&w>B81Eg{`n{5>ZkC^p7u$f{%vf%ec84+2113~WJVHRLNd4{__Dvr@Axgtd@S4y zCgaEpPo5qKqA0_fl*Q1^BGDKRCOdIC7CE0rk_V)mJPV9if^*w8P*JIU#G?Ak^JVJG zfxP;4C&tpsL2pAXHy(WwuOuKt`jX+I#X3fy7xBdl#tG2>U~H;#2~uf<#NiV_vc>%i z2B$Uplir53G{24xr3ba!Wl2diPU*HF!}<%mC-E+5MW8@2t0NhhfA=mInbf(dMm2v- z_de=q@CbeGA*4*3Fg75g^YDB*Q05E$~=;&)JSv`P(;4h zN2zPuXp)D?bH;hbYbm^LzlF$;=n=Z10S$rQU!5xAH-k#xE2!iEmUE0?q|&>&{#yh7 zOnkR`siL(U_pCQe0_neSRW9-Xy$1tlqY3W?<~e_h@Smm#*-#y$69%ngGcj_;0x|_V%lda?!z9= zSMY@FnHNGgbRia$4GzhPoB=DwGd~{ikxGG%3FkkdJT9PbLt9r@K~AC;yA@=(VfeYv^6>j=|;#er!M02H&g8oB#&8 z1Tkmx1qn3NOU{p0`7U;`978Ypwj$-%6=0szfy@E$vzFtM7%3R~8aXo$U=w!QL+3vV zK&Dg!dk_K#{vt@l7N8eF?c1Zff)~@ESWY*N0Iqs8FA4DDYdgCoK<+IUR?YQv_ksM0b=15l{i*1klWsce#Lb9Q3$FeOHZN_0!R3 zfO{0AaC2;?_)fvn{3!WB%e5f%(e2qh2|~z^3!l$calL|oN=Y~QPQ84|+z0Z;2ef)w zRgUxq`k|#!Ljg76WPJW+9p@|lCrsU_eymrk*YxXaLAhTD$wHRob{{^qnT36rd%HC z=Ixi3)S%bRAZjxr5zBY5@U8YDoE+FwO6`*0+@)T|cbuJm3CGxN2nxYnspd7%f}hUm zX744Nn37UG>{}AK-BGFaIYVA?@rs<6YLz>EPNG8oC)4IWR~RHGh*dOgF5^$Y>6cQj zkohu#(VUp-@hKzZp-QYf^G-0-mX>d~PEfDFfE@h-lJj*$aS;m`Y~+G(^LY_MzE*2u z9R3l8ws?y6dp9MbW{S)`cp(@i>#h9xY;M~hJx9WY@-zH6Ax%c4vzeaG1<#_f*V(-! zFNSIXQ?(2w41*wBb0lxecQMxy?DY}E{YSG zwTrvPfnm={Lg1jKV~H9khiCtiag{;p#}=D=DJvYy69jn#rdY;mereDoME0Y`I0I$~5O=Z~_18i#^> z%usrsApVMxXO-$fGy9O>?|fCu0jkfg(XYGRpVpO+ZcKo^TK=G%-7AwtgUzmFgfr zcTG7DKc-jIFmoJVNwIUnGvnbhH`#pD8k2x)8kBU@)vqHo=axWRsfgnlgQwO4WxU6V z(cm|45Bs7C>~dj0H8*?Ig{E<)6<24!kp@5FmG8a(u$dE|f0ztA;lsnzY=1?^<;JZ( zh)BAFnw_KS%YWN8R&Cl9?AF>O_H-Cg`x@$J-&H4CgD8I~PA`=0#nCO$1wJh>NX`4F zqgv#`(}t5h!eFDq{s>iF&9&CBAv4w(A*{p%GY*cvELNUF!4{)Oro3w?c>R8wOUmB3 z_ZkbqBMk>QH2HzDMifD5y9O3J2%`A+sA2zCXMfEF5VG-ez0v>5T;AtT0)32l!6KFQ zEl(29V6;qX%;dxZQu=|#6(G*X8t!rT7Yb=1hrs8=^1jL38&!F>Z^@ zDiUJA%x(*!+z+AcH5Kc0vz3b<&2@3nL+1Jfu?L>9F7UZO)Qu@tH?5p_@2-j*V+Gsn zDi7ToHU;hV(2j>XFm%cON(?q@f3tUgd9bjbKmD2oi?%71F?a^q^{0NL-&Kx3U2-?3 zb=cdGm<#x-p8x;ebi7+(TK3^q7TTW|UMUsV#ye4Z*U2a-<7}}HSnW|u2JmzqtiL(C z*hFGQ=REdyn10CuM?beBIz-&ls42#w?)hSrO^omy;8@70DYgU)ao z{_*Tg^u58pQV-ni)>1Hg>G?fIPPXK1E)nPVZpEI;yVCcjWfc-vU7~W<5R{||TJWTp z(FtI@Iqyk!R(Z;!!Fz>TL+nS-J`)KTGoMl+Ug9@P#@Bs_^ykzo7%cb~D+sN4ji(Ky zQW*v12yN^AGW|^{+^!;Xp;R118v;BO8~Wo!+F{gVR(Di9t0Eb$%g(ZoLf2z(KGG?H z>&xh#VuMuN7w)1J<;7R9-|oCAuHc2ho&hVZ`Fp*Sr*gf`8FUIDCC~7pGli7q)buYH uo}5rnTNuqJ^kauv@r48$fW_dvyunQKanI?+ZvKS@l)dGG{WALh5aH!^}r*&bPj&(*NOLP}!!zqC&uca>C@c z_~tsV(|WRqo3|CwCf!e?*|pX7gKT{U;Wd?0RxuHc&wCxOwU1T z{Ck~%#FNd8Z@>V(IpNu7BT zGeuN4>>66VEb<&^(W-(OyRw3!nOLmJN&;5Dx?YGw)aTdWzzDlVL&S3^V4a@4thWqxm~eeK!&W^Zv%!T5otsR8wT{eHr9m`NsrW6*sz5_> zx)a7~lilhiBl+a1P7{K|k#{*`yklR^i^gP-=+_0!BApnyHo2Z}9TPJ* zS)lM%8<+vwL0HFxoiFI0XqA+oWz^zTmOV<;`=gnj&}vRYlbrX8cvR@JAdSozT&ki1 zH6a&R#b?CQe-mVdg`c>pCp-Id$$9(9e~?)m^%&gB=TKEg_AIC+&1A!@?YVRa`J_IY zfUH_&Kh+NVaHhk$?3GjxkbW`!bt*?-Ki%_)GWr)d(5{ZDA&X<@75wn@)A8?VVwd2| z-MWxxKe{AWd~D}DV=xXTk3iqZjiA8mkU%%5d!S)Ac>mn*n2PQ$#>v7P`i=HSuR;7xNhLI+*m^L@YSfhA^zNYpbjq~?J%n#;al;y5sapUOmR4<)RwwI2g zT+akRQVPEOub2u*4OG z+n`0%XP@zHocI0;g0}J2V^14K?8?c@IoR&skumGWnl*tcHudtCEscvirpx0JXV$nP zvU!r8p_uy-NrkaJ>XiRfNPQX5SRhyE*b~In4a1h+8c;N3TNa?lYIE^@ju_j7MP~$* zQ{81`aN67gN~^lZ=8K7+AzPB3Z~y$yGKEA0d?~D+X!W?v%}d57PR8{z(~Ef*Em~}5 zKOs*^Wss$On!x-r=&?{y2MRM@v{IJFD8(Q+TBAA2rb)D{uF)VaTa`?pkh>sFon5UKb<@P2$o-Er=M{ zAI@|&|2i@f7^P_0nF~c+6Q!Y1mkm;_4NO$|ou(!uWA0Ha-tK<-c*wsNKE}w@jI|hR zHe>RLMstQvm#!-r6tKj+KM*@N3g%=CMS-Up8U(fQB!!OzhQAD8Eju(%Sp$~Y8(s&} zWNQ2m>084*&PExkVdUTEhl7Hz#-s>PbW=fot{xE}HvjCw=Jf&>^FU9U52R>`tcu*! z7QG$43iTbGpd+r;Vjq)R5{nmZ@eUtw@%7a};8P`GMM@X1uoNTN@XWOriqi`U`qSo5Tatpd;V;EhSIP-f(Fc z-4_oTvQX2B#1Ad_89C#!<)a!$4?e#u>e`nW;fm|p=f>=dGlQ``+R?ouZ7aWViwq3e z&~y7P4QJeQpLue}@eB^2Gbya`Ou6l>@ig|uZ!hj|Y=tg!-#Sa+DL5*$wg+5yc%Nx&Oc~^L&4@R^ zH^iu8BOc*|&|ueo@k+PKtXep2qM>+HnowF}qQlC{Flp1&#w;xJ(3n|tsB!j6@dgLg z@^t&Pc`M5!`q4vk=GOv=Wt>~Xv>FemQFb}44HJUxVG+qieR3-})$Yl^>2`bbe-+)o z95f+k?7fjug8?Buv{}`lw;;}zsT9K~!>R2WZE4e2^Q@q2uAj=sG zE>im6(xuXNupw?bGMzI9R%w5Dr|dBFxU)~nM&|`}ZpB8wVocUnej#0Y4j(qj9||62 zoHc!v^v@>SdQ+lqQD|iZ$dM z^k|2ajw?*;^-Ld}Grh~nFr+Xd;S@3dj%9Udl zV_+hA^72THfAN&26vw5Y2}o#gv-iQS8~+%Obrj=gTtt;TcE(YzCy=t{*5t-R`OYoP zv17A9!R)uC8f<*-&`xztDq>LLc2q7hjm#Q1nR#7mBTku7QBU! zT?yBFbOv3m=b5@c&s9l{;=8t#ja@?XYq2zQE-lWzp8H|Sv)##=nl@HS@+28x zMe2^}3reK{otJTH=mIOP;%VqsnmoGXkSG!WuM;hoz01bQb}=&I=6}^1)p35W5PL$_ z)J=2zM|vIyg-e5mk~9&e$V7U3je8wZq?Zm|h&sk%W2Y%%UjD#M>E)rob3SDdX&?2$*<+Xm>epLwZ8-@-Uz~h6r13p-6RaT++aJHjkJsOQmL4w1_}e6u!{sk= zHbrK)0(}lfQ#y~8Jo6n7%N==NUj)Q-d`bLSK7u_{ zy_`DLGbUTUP#nXPma*^Be`J$s03{t4}#=i^U-eIh3^4pPr@c5`?qP zujXB3v%tb8`dp$yU1Al9K%%HI|9Q?EjF1lh zz#F^wPxy1e$%_%=CL&myHl_~OSHy+s={yYx)Y89Pv|yv_!>dywVAiDZNx-zi;k+1Z z(e6oavRJ0GQVaSZ!Qcy}ZP5bmW|mn=d(g(KcC|Vo2yJ7$*&QSkra;CdDF2(0wre^{ zb)C)n_E^lTa7LbwR|YP-MuWQLlh@q9w1`Np*P_C$LN*v-P)>3Jl3{+1}0|4sc> z<`@O=KJXLpoG$$J2ulp#yAPT+e52)F_skx$9hTotNdYm@ydT?3*hMH!q`RDOd|CBj zXkNBZTwJadj{ZX_8Rd)@LP;?m>Zc@{1r^|*yX?y?g$2Sl~hf{UEW~fHBn1- zY@W}jCta)-F)DvDM%N)y4zfhy{3JVA!#KlBku=KR!cEu-+?I5FUe#xM;Bo!XS0%fWQaCkQJEVcVM@^O^!>2}id z&A%|O>9ZeXLeD&2P@}<8=>@aezM0L2K+dBaorkS$FkfQve9tMY$QK0`uf(AyJz)5> znaOQ(K$3W_fXb5{iYszlml^qZc;+AT-&O%dGadFn^kKd&OtD$>Q}{U8&TfcvW)ZR1M^U>>tHd3S5zEh<=gx$f}TPU&P~j6~7EJ2IE>6#@Nh zb-Mp=oGE-CZhjGo9F#%Jz52pNSESB$E$u2HY&n-<7-q(-kx2JIi1u<5Q(LzCo>`3k z-F$HUV!7+?-_Sjh2^`Q`s;BAT~<>aq>HtI^zVGJj6Q+f4i1!QzHnAeN)9=>Fdb zNB0ewN_EFgBFsc7QB_*tSDMly1~}fRlpwKJdU>#7C!aaaHZrxl3~2OqRwM< zZm3*MWBIhEx4F}n_2_q8Le3pG~L+VC%EP zvtv((#+Vfiy?z2bS8G{(fNT60cp=eNXB9NMlJ+5{YX67?7p56VcAtg*SMBW1!^*j> zEoz&M$dm5IaZh3vK0OzZ{0CS}=42JMelvw=m zk=bPnc?0%^u*qW?$BLm+=aid<*7Sr~X6)Ds>4w_o9&!Kk%KG(E&co3=UZH74u@twi zB1aQ23Eg44A~cUO7B5e&QDQK*6NL#h%V4V)PUJ(Qcuw0D^Eu(mbw@pbj(+-p@zPtQ zDK5RhdOb7_NCBoLYve>S`P=)!MuH=|vl6rERxjOR*&R#=N%}An=wgJ9uo&^8A_tSg<4^ zm3jE5TBB_d8Z2b$cRMMat7)#@;hUArABrjd#codkFf*1`^v~@WWAwrQpO*$mkD{^# zCmAfpG9mWBbcmhdVr!;;9Ja`I>cu}V{gJhuS%+5H1FPl(&0iM?H1%h zC7?z=WLFE=b_`_@2Sq}I_qLh@~aS~8Yo zm;8-)@F2IfuTLgS%RB&!A)G3ls=QD5`58_)YL0i2*54GXHSU7a3w_0mRgPUt$EN);uj_I!qIAMGcmy6wiDHdTfl# zXNK}q^{(5gMbEdTT=Vl+Qvv7AFbpcZFvTz2*EF$Q91Iy+Y!@u6jbYX&ZOuX$I2^bX{0Bwj#@@*0nIU+e0Yr-* zvFXH^-=D&+k1=e~C-gHcpNDlZh=0a5D``>*)d1bPKcev{+u7+xzRqWgOa$yW88yAI_P7md?(h{VN{l|B%3Usxs4CL87{sxGkApv5 zayN0Y3xZ5c^acF2!=)PbBRsms03V4r+1nG|sZW1}qv4~%i4IC$nY&jDi(nnErpVcy z{ZXa4V2Fcp6a1A_D?Vu&M(~%SSbx(}4zqu>US};QMcd#4ljAsBk8!m*e>`Q==gJrz zbeRzF8s*{xS3hmB8t52p)BVh2EgQFd40Cths9k#o=Z4=`(y=C3*`;8Y0;zLIN7Bh{ z?nRpN$|^_O$}+S4)B-4o8AK#18PZLn(}vdK^eLU=8VvvYR^{B&wK&GS7P_B!+}dZ` z=3q-1o=fg-E8vWk(fjKua3xhtk57{#8}dGhpAkR8hTUfE2TS^=fsx^BUCNlzga_t{ z4R<|l@O!mX4Fv9RB>>hcOVtYp1WNIqmR5=-6a`Uk#RvL)_D;Fr&o7hh`-6JO(2#TD zf@Or9TrMON2&tWx1viRyYT}-JDkK;$Z&}~u)f%)P7-9S66SF~<<;}aXwCNoG%pz;C z`=dAh)mVC_0GER_3Z$fsN775tMqi{hD9q*)8uXX{kyd9E0c>z6MQM5~xzjUX$`rXm z6}`&3v31V>>L8ClV_O5MI17kI)Z7Qsy?aS*cGOwqTrQ{g0h%do_9T(8A~ip9YBv-O zANk;q&|Peg`hEZ1$H6*ohcWL^&{%lw;()4woSjO+fc-u0?tzOvcSmY3gyjmpI=4n~ zNQ(!&BZ%U{}RYya|vI+c; zx!$ogTXbwTlve`qCD=~%WvW2h|t4=dMSClwT8-zdmi4zLG)pRE)Nd^FQa^| zYnd*++daEb~E!MX~HZFuvWc-fRCs< zX^hLM*>$#7_ytibJbrnV*gXLbB|)ue-5oB#6w%V=8?guBR6uz{D2){s{X`~n3|aH? z_EA_luyyRfj-9y7?0_de65g+m+@QKi9S#>Sx&c1 z49tqcHXvDShmpc4Yp=}SO&FIzluaM7xA-fP~djTe=E*{an1 z*6EN|CiwTc51{mYEC>D3!Iq>g&C}Y0g{N5}w8##^^5Q|1gh(y;;PP5yn}0Bai(Nb0YpU)3A6kAid|Vtuq5?{q!(MYNRtGq_+220L za~}=t`?e%GA@mzI0JqlG3KP5c#;@Z`X^Hof?EmRn_XR8`ekb`~;JLR~zEfWNq((tbykLH)jg;eJ@@DLh zpshASdK^C8(!Berh40Azsan{v`>(ZcuhJZK-2}cVXb}_e9c`H*W7LK| zD5!v@-}?|IrV3qaY9z0D`IuqHo8MO1d&OCSF%d&_$JXQH=BN-q@{MUjU%4eg6VHcJ zIR0^4X5jGV&S}?F+3`BRW!ZAAgFeCIG^C0Qle^y5*gkpFQ7%@c&H^=BysV;b)fP8T z?Uq$HcU6zbHDhhBo^@kgJVsSrpr*)36py*QPeD*gz3=dBP=2myMSH7qS(9h}Q8|{p z3*L&cn40LV67;G_`aY7wxCp=w1iY!Ns*kED3x zlNTxFe*b08__xn?%Cgc(*}uDfpQ^{335Rm1*(AO6hpJ;12TkyI*yorQKtT z0f4YxiKsU!Ot2Z4-iwM=qjwwKi7R(+_v*aouzmfxOl_+^O}6^h-6wuE9kFN_nTUx(=5h>PuXY3B&)0qdiERtVS9HjI1*>V_%W$7uN!I}Q0|suQct zd0GfFlilSRyF{#QoWaWZHhb&diM_qtXV z>JznKRt;z^Y24(I$D2+alV|oFW+@Hnf#XF(Bg1R|TSbAMPw@UcONP=)700$3ZO9$( zQqjzD2`s!oRtQV8GVAoaw|e!8jM3)hJ7AnFK%4mJwp#D0EXK_n5G|Pn!41nhU4auIA;koA8+=P!=;Ei_TuwiMTEa;T_CF8Z1q3d{; zot!uSekjUinK*83g!K5x2`LgeKBhoUiuNG(k3pGdKUzpTOBy?$&<;j|(Bv_7lNp30)TyTOb+--_Jg*Ya*#y zvAJ)w3$stY-2j~#Q6Ny7;n6N`@;3(Q1L*_G>u`W4X>)vDjf7De<=Z+j4-DFVkTu+y7@=Ek1fnm8avJni zq|BdwI%K_lJ+9}2Nle^1Dz((QiSVj=rO5qWs+!!rDgx95&+=@p7N1%E92x?7WS)-M z5AII!wAktf#M${WT%e&TI1OY zvrPP@Z3hZCfDfJaKb85NCYIRhBZ^CtIaA4Pq#-uaDaT$~02{`9ljXco(PgB9Df@28 zfBe@3q$e}m7UkTyLSBD-arKeX*f&J6nopJsm9mV0^halBIJ@8CmK+T)@w=m!dH@bH zJ+Dr5miXP~k|(?DwEwonosaQ93>`>{`IcWo<$fBaFjp0+p>gEG;NtrI36|UGj6G9W zESRv-vK;i7YPT0i+t`9a&-H;^7cK+UsPtC}U=_G%^YajW2v6Y=viZtX0ough>>Ap` zdQ2}i+FQ5t-T&ticl}S0W!;5(`(g3qR}TFPf)fvXWUl-I{B+5O`l1i@yqf4W z{V!P;2PeZF>?|J741cx{4Nvul5VQ2=4S(e9UEOrZcdUjs^d49@9jW)C^ROW1u$k8D zy+o*}$^0zae+~sj0VORaqNXV$TADJpsC*UF+XSxPWAZQ85LRCG*PP;#J1fCl4=2gu zX;$D0%;RKev2+g5ab2Ux!^WG=4TA$nli`|8Hrzi@EkSy|0>?i5?~x6CY_m2|`N=>8 z(IN%)CuQm1ji~s(2qXp7Uj?u=qN9h9(<5Xm-28W-{I6uUj~Wdq&e;p{PF&w!L&)y% zP9)dJYI9K88*m%#jr!mR|8|u^*XnTNlfLw2=xochisofU0p;RmHMg{#1Sk+$$PP<< zl~{r6y%eWMW|(D>ivpg4ja=d_$8-ho1pD6c@w#cLq9^uKW6YLmc~zEf2x-iPMNzu{ zS2QqRqThoZ!dN6E6fb#x0twXZNJ-46YU`j>3RboB^yL=56pUo^zm|ZaNslZT;Gq~@ zA59{6N7=|VZb`DM z!W5$DzkHkSofxx(s4pZ#g|}dVsc+f_VLunVc(E7WWBYK!2^=3CXt$Gn9Q+7R9gG=N zGX>^zXAr&g-SPL=T(RPAD<$_tQ4xFBqKVsFyhVmeJVr&TekTCBt=qbFOvBdEiZ}C@<Ly6E0>IsxfLuZS&dr{q=OLzo z{1Iv|(cqcz08?Iz0^)?0K%`ggd(4&og<Mg!_gBz?H^IqJ;_O1px3D}8Em;)oB4aAkn@-lLb382JKJjZ<#FQJh;_Q|`zp6FK z-vm-BoDy&K9)@d9vlcti{g|ns$^{K&!ioU(#ucLhUdr(&_{suvIhsg&n(wKW-G4og zRrl2k+7uzmpWHVmtBOBz+r=N-EffS3=2Ec1f7ZOy>zv*9&Ch=Ll84=rEAqeE%1b|y zcE227Z9d(algppYew zf3;WigS_6cZlewAk{dN^&qtU5lPGhB33e!7sWrapB*%+j)T3JX*oref57IWf+2fOO zq*Drdw!kb*7u1(Im4)?LJE-C%w{wHn$Ke$L$hIDrv!uBb-Lh4VoOpyNz9O0$HN+j# zBU7^xzlFr|Uz%lo`9JN}q7rai#gcZB*KYj`8)swh8hg{C-jPWwJd9X2UV89pc{O@^ zx}(qan9^P0WOwEt!E*-k^a%Mr?^Ig<0qaiuPR@XxpzyD;-|Aa${8ma+cC-~BBRYH_Q zFatk_e3IdzjI1@8p?7?E#Y0DZIG{Epi?%FgZ<=q>ydz>Lf=@>M{Ws+YOtsBq@4I6E zDQP|-BLH?4!gBp|)9vXb?>IixZN5aFXcTR+H48_(p!jV~ldwS*@s=g_qnlwcOm*C~ zKAoo5YoixghX;urY~?qAcm|2ebfb=ha8<5SS{=u9fYA-jKrS&*#*==#%OxzGUv07L z!WB=^!8~QH;D3o*^K++wFBr9LieiC!T)mfXTTfuQ-AyH4`gmdvTf~@MFUu!5PVSlK zj*Le&0D6N2@wVjtF?1up9;XT$T8h`z%xymMOOqW%>CSb1=%n6?M6knYq_^+@n^b5Ql1cvJDX9wivvg}v z&S$(%{jW%tU;5s)y}wZ*%$+;G3iT-EaoKsqkEV`S7Vy zvp=HH3Krrfy<^{hRJBesz7v?8#sY<6+8tBt-0(I9@c9T6GtVgUBEH|9)7j9tT=Nur zt7)`;nV;E5>KSn^+9uC@r=&ISS-&iVYFP^x09u}yC9|JMF&TrV2YhgA}d`F=2mZ99S z>^v*Wd9SR3y+e)zp6F>*tb!RDdP}1yXnLIycv)B3;?kMYWcd?1l}BIe_;$5oBJe#f z{7Uie7s{`*ggz@2!IGLYMye~FY$P;+`WYC2WyuK3&*gYTcc=3>rfk}LhSL_6(5Yih zI(`slrrMThclRexShy;-Or~z7E;Bq)O}Vhlvf3<5fOHeVcvG^tFAa zYX#om|HbepsI^|mOkRU>dR)D?iU~YK+YYe)VFWd$%&AL-K_2UfI1OwCVQtv1IxT=? zdTyLFQF+_G>?B2y$b`%2>T`YL#tw~3s!zraNv5rHi91*n0r6)D+KTro1u>7fWBTBt z6`1pDZ%%zFM5AyhA{aX>8p>QtPw^fy&31X+Ei_(M==M50Jk0CztBX@}N+Vz>g@(xB zm?+kFq+eR(6d@%FN<&6H8Olry8VV4pC@(@W12>L?MM$fJyg~(Y!4B%lVwO)DX0tz) zPyEj9{Y{*HD!%>|SI8x3cA{SqmBeAdI+eKI?6-xcffG5lee{_oA1Y@UVxnFUG+$GB zP)%()8WZpLp{1k8Cx{$58pP+ z7op>X4=UQ7n33g|tawStB!z)UVe;_0U|S4kJi>eK)9Oo2O(4Z`R~;>m({p19&7GTg zAR#_adSJ-`MTb`{VN(|+0&xC}u`TT0%2Yz9$n<1DoY`a!(Q?Y0-|ihXwqg>3+)#Bt z`?!2P>Vx?kV>GAn+MHSppA13#B_DlZt?P19`!R<8O?NV|aFk{5m^*YY(7d;f;iUik z@3$CS>&EPnq9m6fyFNa1HLLEm{mFDz{C%Ul*q=L0d?!Hkp%(_G>}r!1-> z3vJmNklEg>9CR;eaxnA{`qKX{nM$sYYx&_*QsL|~{YQIW$|86P&Ja+%{Tn=Ho-l%>>(mdw&^u2-#3mdW$ zixeYlE07jzZwQU&;JLg=KtR*bTj`IiGfJ$qp&V?%{GvlGuX`y=P&G(GXybIgi=mjS zzjGk$mkk+k+?NWbXY7;U^}RvkAAQ5aX6dL~*}FGoIdVcY0&w=A9ZG6Ql4bLm(Rsxw z4$(P+EY28Fa!JO^n3~wp75cxXaVX$3MFV zc1jAA-NKMjbUHVACyC_$NPt7-ks1_+DTC=Rr7PH~O&EyrOuSRQ{F)S>TI1<>`Cfryu$tq1m7+`&GXoG=`mJ zh1ciZ*$8@hq(-4=g7M&~-UmuQCH|)Or}ji*qdElm7_n~AxV;>w5!ej04$gu7kNgs! z6wazkyBjY&K*jJN8X{yma-E* z9vYrkStWKgknO?(o9aC>wGp81^)X?;B$N8qVLNl z6(aoN0y3CJWtyU(+L(&jELvKYswv*J9<82lHt?vUGFd0^4u2b|@IiL=Ur&m$!DRhM z=x_S~x(E3toNv594NI0v1;i3O_0EX=#RR_VqL9-3Xe$qCB3SvRn^zdZHPbtTXWR7# zJDyF^{fSX`_?u)%)8#Qkre&U;Ue}WXhQcY~j-o&VNbzNh2zWj>+^)3AHW)O+PHLy= z886T9AtNurWTYExRijUp&aHcHYTXD>N~5D`xy4F8V7xZWNN=uQ);{UeZHUi&B?AKW z+dVEd$z(l`LcPSIv#+TWZSk~II+N&plbr6id$yzN$W)zO3PQr<91ON5-uvxMTDa7@ z%XUrAcH^<@muI9wrJCq$XZDBCR8cZfcQLD_BBKVL2Ui;WvU6r>`rqMOJhl_`G|AlA zh2CbbY#I)bWTe>{1}sEODSBX!?}69~!_L8}KcK;Z4qn%v(-r=X@{Ncpwn%B z*;!TQaeGOP8cb1dQZL6z2F98eq3;wjQjWdr4JL}RBa5<~R<3!~2W0<}=?$!<4StY) zO#D{*JFEK=D=agPonu)ny#56;kiB%12{J^m@1T^ig(4C%FUlitF$uk+zSD_C#S$GtPmqVjMKOJ4G;9SZ3mS0F`Qxy?j9K~3E0 zNV*MWnPUdCJTXKjLQ{c{M;!Ja#xI(mYAlD5GoNQZixPtr=5eGKua8|(qS59bOwrHx zAN2;}p8LdEr|GoOGqQJ?D??yCf0T{;ZE$9F>C!#xmvpa^m`UH_E)ZL!rY118ryri% z>1Qyp8M-{Yly=iW{{_;v6+6*$yu2utyRq_Axoe5ynN3P~fGL{#HO}3O#2|ud8W4uV2xR4UYYiDB&`* zq?B=oKIsX~n8t(tpLWJPb{of8sRNmcU&y)j^}efVimJTp?ck@BcCT40LAP#eLiGycKX1mI@c9mRILMx zBew&`89q$R>&8w!x%JHuLg_U@|Cn6;Cwc$B0+V6x-C+`7$No?^c3U1w%u|W|7J<>9 zI5xs6VUEN}sGN9UDY9eHE0J2F*>8)p=&U>%u%9%Rr3}-Hl9{geZi&r})!G%n;V{}X zD4aNV06EFlhQR0XBVu-Z`-D=$b`?M zhoCY_zgNv1$@|jelzuh>(BeQh%#B$kln7F+t|oy|RV(`?2K~ zJ1;!2p8Z$5l+|C@i{}TOtg8jg0R6~?c9i$uWq>$9!m)#RK6CAm`vZFb)&BO3&prB) z%tesMeffCz5OO0^R=PLBCq{KS?=Bck#m9G;Y*x_BD?h2(s&YOf?I1>IGeeTWKY26* z7-c|myqCH5lxv(OYrHGFdc1?@_9D`UME|Uwi0=n{Jg$#$?=KBIO+ILg>dd7#D}1S~%DN$B+}v(AFmUqgbnoB5lgrbsCzfb0@?w{qhhP*m z2`nscz{nmb@Z$r-%mwPxmKVcZ<~c*Xx2d%ri8ot!K5MN4sJrDRE}it}4mNPdhw#T0 z25PieFoYf+FDOdVNoo5U!3Y|eB?1czvpGjLY6e$aQ(EI}3`?1s9{#gv(2RI%Tv0Bp zx$(fBN5jm#m((GVZ4OLo)j06hiT#y`<@FeFjerbXOw6;E3ag|YP{U(*Iim2dbvaQU z#x-3$vBIRIjt5wFBa=5GkspH2h1XNIHb!^& ziMEcOGfAw3MlQryvWeC`u8hGE=Lj16E14fr``l!VXwiv2M2~EG11>Wh6lX<-#Bkx^ zt#f?+!yq7MWr-So2<>lgUwBx2thCBtQ6}RjTCL%aW3&nCvRH6y2<;@kZ3)3xG}H+& z312J0bp=cby0OezMY-W2BdJdUbWO7nWpU+R z_k_NIB;RSjzH$eay=3e+TGO}7{-`Jak<$8Z`Ao~lnQ)vgAAH7gTbuvarWo5CWHmn{ zRq2tsUd#SW%)7G6xwE6Cr&c7=(&d@j|L1+->dBa6j|#|S-~zu*tnfGBzr=WA=WV?e zzldOd9jV5j8}ISHmc+}c4783lgAi>RPCrBc-MQo7t&3}texCt`mO`RKlLIr?>Z8*b zTq*^{Qn?nLNHR1;&M@|gAz^FZ&&U|7nJubg4gpM|m#Y$E^SG^t7yW#8ozghPGEu1` zP5oMKgFw4;8+~~jERxJ(9IP{=tmb$Az{01WUK=kv&wJfInEE7m#0HVj2)ke|m6jng zo}km&D-1L0B??Vizp)V!g{FF=+;2%<6U9XyK&ahqcKWVjjGzq5f=s%XR3lGbbj;s9Rf-Ysy~P z`}>o=*1yNv^#9a|iS;b+`Hk&tWNm%`2SEPEjwZiY;K@rT|-JzdYJm&vCe zv0_p)%lPlbUvJ)zY0D?_Uur0@G0;7*!+bnvA-w#O!)n!ReB$!JS_N=AR_rq-q=LMT7f3wQxTbnpu`cTO0_mY*-!OdA+y|!RzgWTqt0~ci@}>06 z4c-464cA=PkujzY#TNcf=A}M}&OKE|CxU%gKTc9wTYFskeo5BvfYcZpn*A%*WpbbkvF=sEkNp> z(rOMA%BZ;9;8Fn1iFBZhS#0XGaAtRlIuyrFs)K0+LHY<9i;VYkFS*d_{#|#M-fL24 zXiI#DZYlb%)Yju&aMp>*ooMXS?{u0QWG2>bvu&>Cqnz)i&zmp$>%Nxen__ma(@cIz zVjmP{^-H}HPgP`$#GDNux^E)i`*PCdC2iFww07klr0szJJ#;ULRgsW=cb1@F$wg4E zz?!=jSKENXq>%RNVE&&lXdc8n8xT%kO1cY(sm)mHi#G3W#er;tb-EMzQ1 ztk%DkC-eZ?&Oy=eE^Qb7rK)KQNptM!KxDs)e8w$EEBX8+I`jM5pcVoDPUH(7N<`-v zZLQ`!ft<-PyN>NzL~Q`&6ifcM29e~8%P@~CkGE0WGvRfk4K>Ghm$N7^&ch*1>bBC? zCcnq0n`ZlFaN_;PZzuj8t|wfy|DA<4D0Fb13%=)i<0?3Mg9dg~QO;i~FY_iLQe) zT|g7fh`JmXFnyJ;UV%Gn3EbigEQt*7iVT*1=eeZVxr(m6#2TWu$~JNpeP8H#NVjq2 zx8ahI*43)Z6GdWh=lIM`oL=|i4_=KJF|e(5>36<5YIwhj|8Vo>6i=T;OSbXHf`X#O z9C7*{DtBThj(filJqc$${nNL59wMVm;G z1}&-2KS@p96i5iR5Bwo~zz*BlnES4ePWvXSa!r;`zS_c0$;AoiNkl=X@no--*?kRDfWC}B3;^~iG&O|3o5BhV8h30 zCtaN{Gj998S9-bsDOi=dpEnz|vYv#|SZ7=(^%)ghY`f)1H(22aq;)ie%zcPYNLOiDmh-5*}iEBnl6G?S@y7`DXg9bI@h6 zdVTo}cl|_Y`V+s9*djnpP@D9J_*JRtXlMfhVdVX{6;_CJSTg!THy#a>B}Q&&Gsu;F%-JE=qqBwuD;yY zPj<0nzbyGrK7<=-2kn6cgkZoTA4Zlq>h|;qdGF-*Ih@8zV4Z>J{j2wg%*+{^H^%#V ze4wHA1@XINXd%!#80Y_cvf5Wj#1Xsh0U!3U1)F8LuC``-FX04V*L7a{Oi6B`nNftV~7LA*v|J-VH*#uH)Y?{q=wJ#W=0F!Xm8sBdps4 zu=Sv(+(19r{L_KUDJ)4Fe$P|Nr?>wzp%t_TDpd9X+!_*?ilSP)^vWvW4lRFC~TUvi3~BDyAcN1UL+J4B{vvrlhEtEfAMvnFY_ZoNZI=O<=dn!k8=@w&#Ld2jlxQfEuw zNT}56FSC7uj*dmhe^R(Z<`OLPhjR0Y{_irQylb^PYI;`6zPZ{TF6p}V8JbL(S0-99 zHfD7mpXA6lh_NOrTE~{=%3?}F+kTFV35iQ!Un2z(y*4EmqkT`Qs;O0}ets$3crKMu z|E}T=JrZcGAAv(eNXz;J#LnO*t!om6(1y#B)*)%AafR!aS5>H$ea?cdWbv4BtvP&Y zni8+7On5KW5}jj6RS}uYC+aMkxoD=KpHL2cr;uFzI*+h`JEJ~r{b`y;{mbl6%ct&~pg&YacRU(GnkRF%LI#K2NT)JrwN~VNS^PF{G@;{C5Tw(~{|Du=Z;! zYfr(W*FF4&Qs)Mq_;xY!ADNA4N<~Ib2Pe^vHOi|D%?y>_1=H_U^aFJpGG!~@Y)&p&x83m^}X z{^_BtVt4id#XV*A{&MGeusw0>eIc`30+^mss^&e>8~VJOU^MoKnu&V3a$EGmhy(8B zTL z$2zNe>VbWF9*b94%nJMJS>_A~iZX3nU8G3X{2h>Bz%p9lmOf)(Lz^)l7ivIgP}KI_ z0$sqTXEe;hgOUnsr{{!xllBDoPyk!+p8%5g=bEd~@blq&t}Z#wAv&}^dSD`Gj~)OT zK{Y9BIR81f^|*?C><%Dcb%|h$uYc3;QJ#tZz#LNGU6Dp{syCdkOTpXoNMZ%vraPW|wa;5X z^U_Gb>j!koVeDCW2t7_{xvW02*;1I)=51k%LxQhl6h&w zmt;}J#BM9fs_gAeRiM!Dx0ImBJj~<@JJ|jIEL554vtMTJ^>-c*=j)Tk44_yE*eOYF zvw`S`$5J%hN@W_z`Pj=-mfjX`c@;~l>D^gD8%U?v^Q1Eiiz&bl98m?9!Qo{2B39eZ z<}bAR%KwBfpPlPPAwMh@aYJtB;mDzZ+-*~}>04zxrBLw#2p$a<0a*P*5)3%BJ2BQ` zj3&XbPa~Jdt%)kewv4Jno)v5dN9)s-9wZ{F7Nz<1Xto~rfm8z6Jwz+<&@#bt${@mS z=}C6=!@@=ezzP&8hV0@D4^;B)v4`()_r%t-7PU*;H;vq=j#U>)@AzDeW#w3^3v)We zmza2*Xj__;$d_rs3>GhDe4ccy2^`_eI#f1S6e(x@KW-+H`$AAUsZJ# z#b%lBI!-j09y**FDfCEC(t@M%%FVQd7J_A9KN;B;U??PC*Kn*gADdLlfF##qEgsWU zYuQ0)FCy22Jn-fAbBD7KGSTP9O>uodvl1_Fv~8S|m1pSTi2b}atwTNOQWl$#>369m z8_TyU1R16juKpCTbQ>(;FI@c2PGMyWD<6c^YiH2uyn6G|@!Kl1A1=b0p1W`3rbV{I zMVwcF&Hn|iU&D9z*{!GhFSVVdGR!=atS5JSx3W(1?(XH~Yt&InQ&tY2x)xtl z`Aj!4`)(jjWO!Pli6x#P4+eKzXPkM~BkD!7nl4oq zH4l+=9fsUsXe8rl_bT0)>N~y%m*s+(5fKFWvTN?}R`zg*#_0L*N+nr>!+trL!(6o; zaocMgArfF2vS+*t8$3YJiv7I}cVFBY*}9K=>-QCX5MmpP{r*_PQ=la};Ndr@3Hh z6|2a};bPVEuBzVAEGA6SEuXzovYR;Qv)fl#QG1ue%&u`he;F#P=B)Lp6R0pu-9u*8utwnjNM^G>UaFT04;)gxXdX1xD4$xT z`*-1_jSCCj2PMT`mnmA>dPXt~7|ZWtJW9Vb65wXyqQ}~@U+S*;FW}LQ{%V4a`?M$) zuhiEL*xVn8vVlH?N@@mOyei0Qk=dfZaAnJn0d%L5ZmkLZuw~qRyROYJMei%4tSW`S z?xk(OtDj@^d5l?=+<~*1VdFFbaBkRduK_{RVn4p}F7wN57rGU;MAH+8#9=l!(Opdb=W{|D4kL#{~Hlgvqkmd#9(f9v*rg zT!G)unTlao2cAYjZenySR`vflO>da=FGj~3VFX(Qk!W>{YahN62#pa1U=R~dY7XIj zeHZNhkom>_jm4KexG;AaD1T-D*FXHq%8IkQ!>WtzB;}ePO|r!^fPI+9lx{)2t?eD~ z*noyK{w|TWf6+|TmLMs&g~DyRzM6j7^s6U#VAh0`;GE>GHeqqDm3{e&ObE1})i$Dz zBH)8HTjJx`nr~CzpJ%6ZFGu-+)j+~7R3Kh-$dtRCTzS#93H7$o?IgY`D zss2DDw$<`Hbm{YC946TKV+sDx1`bpUw#ZPqAw>+U6b((&|CsF&%_n##2a}pcs{q_H zaIqK$arE1~rWJ2&3I7hrh>bWp?%SC^X083zE}wk@%rBE}?t0H_x?w$I!q?pIP}@Bv z>9wf9UfHh-YOlW|4llw%bX9K?;fruEXe*g1V>P7_{jiBTfra`xmA{J?0Oe^`tw9s) zif8hUg%1x8-C7J@;0y$wTaQ+d<&xM1@lqA4BqJHMt&1(0f&>Fz+cOjq{wb{)ps^}A zo-`@Wh-esic{3lMTHhxXR@9h&t1*qh`XDs>n->NPdRdm>dA63>jpYYSNL}~dBAMD3 zE?;uVP)aV*^8-}AMSRe{f<*%~ASAPi3f$+GWp{(~^Y&Ld~D{EP- zr~i++?u+_}F&Y$g;_S=p_eQx%{PbUJCNf47=SUr=Xyqs&CqP2=!d+cSTd!(zPwO)zUb|Y|>AvkkNLn+)Qsr2A@#eicXU1Xd; zo#BG@q}@keLo9&y++ueq$@}7$r{gYfN5{#Dr?!7Z*CaiPl-g!z-R}oz?=0e3^f#T_ zTkE;ze_u8~f2|ia780vWof>b26(FIWFFxSci3S-?u?EjLOW4YSe6ucArYGak$YP1j z*_4`BA2+e+QJmZInx8bJOKT0sv;_sKwK^o}cC|@3 z%IS(zIR+J0rcX;YvGk^5eq0rLNCxmNth!Z|MsalE~`VhLJ!t(VZd~HjVl#V+{sE) z_00>A)0$wa^^KipEtSa=x7Rr~(1dX=QgMPh3OL^5)FxWSKfI$CX@4cvZwANR*rkG3`5bv7QfEL z84n+gvz_PJj2TX>f+1<%4%@pn%}3o5-`ocU=Mpt>{JR5gkGf@_bjesAWsL@~)_&RE zU#E~OK{prKIp0O?uarTRng-I>A8bP+@q~v6tu+jDVBgW7i{K+S_|##NvXNNkBhThc zc;eKB2z}OqWSTm&dr6)-zBn^^1%*XvJ;x}`C~Y|jC_eNtm=GfuMl;PmmOi!PAq`z5|bWf4BFYYVv*E5-~f#ym2nWuuD zx8B|&ut)na{I?H}QerBYM+83&PFMDNDfNp)N6fypnK4!1<%cG$$@@!;^2qt=6I<0w zzfb05l(n%Wq8!2l9z_022G=GZF%S^TG29EDzoBM6i)woc4YdVw2^@63ZWPP zluMti%S-q9`T4ZW%&paC*KdNJskgV@Hubu2Sd<+{;E@Zn3Zpa_9Vv6J;C13W)R`md zbe0esjKS{6`_j&(_FPyBuFFB$g@H6Q%!q~k(!Q-eTIHXLu`*_9-bk=~aVsuenQntk z4&<}^0mtPLCeb1t5lUgFhP3c}lKXP{p$*wDXLL!?6)a>bU3{a@m~yLLDNt*olvZwK z7=G89s=Yw?E7Uc@4ri*(~Z)K8&qkdGJBmRKS0WU_Ien}LqFvw;t|*jaYx#iwzK?wygdd7 z4P92Vs1X7_W=Az$j~@=CGDtdJ+A>;X!n&1xIf7+0&kx(*6lP&fC&@u&L8z5@sAAwB zsCH7sOXJlwD@kv2b3Pu~czB9s>^nbF$FV|Luya40O}?~&^P-A&xWGS{ZA=6)jgN?p zU=Q7>j0Oh1)VTdCYkc;{Lm3?(=MWU^5&U(A^NxhX`{AtWY*Hd;tMIF#xx0Hx5zLO7 zHWC`lhenJ{BW;bL3-E()b{inBJCZw_>SJC=i*2~z_?}8<*`Lf+-#^4KB43=Tg2rJD zLnYbDiwtwz)X~t!Uw0YyP0|cVP`o6h70LfL5{GUNKX`19^1ym&`vGk^jm`n`xS2Oov6L;alFx1Oo*>-UmGpE-p#+%z?b~+On~t#i z6Bwt_)A`pMN7&h)Z~PaG^>=8hGY>t5oj89<3XWxayL|}-ENCICU5(fUGuKD5(FQ%w ze!(g=O|8Bs{+^TMVu|8-+vt#AUtH)q5`tkwi}wF*4erQK6{jCV#RFjp!DAoG&fJT0 zLG{vj$tu~c+09j$u)@boSK%1-fCWRxOowRpvJ9@@Z5>#AH8i2dc6Kq>Z6}YbE+Z@t zQ&j$NhU^hkd{cFzEg3Lm=zRF{ z(qdmnERg`9ah_%6%?z`$<+Hx_Au307W^dkMG`(wjs#XL@B>CW&EF;szP;V zi4yB>bFxSm6}L#_qf?5ezN;~&T#ts-km?V9wz7(d_doiw)cE|W5E=U+U$6|(e)0rsx_il(GxdM@cJexF zn)o$kuK{<1%DzLy@Ow>vCpdd)?#aVf8po|_JIvDZU35vLiM z4;~$IM=xkX0vi71%k9(2^Xt3&do2FM*W$8j#^b31#M5DSE(5YpO=fTq9ojG6u>gll zSxzpeHkiMbWQN4A`W!}^RH7zUXZueA#5caNt#Z?>Q5z0mB-b8i;V1|6ZsBFB>2Xxi!)zSmTJHa`}9g{{A6sSlWh$CeF@5eSK1z znwr*JQiJUljBnb>5pXi&M*ImS7gl#LA&OPHl4pVuihGBWZ!gK4&RgI?AMQzwdZ{Q(jp~AfAzYtms*Gw)_0&E z4F5qYTXgS}SN0K6&As#?BlbvupkJ5{hJ<)s)T%@UVKTCzq6nROeizfBhz1j?!#H=n zF(*dLkc<3YOceH)sF%c`j2|j}i;h^E__Y&OrGmI^f$YZ8f^BVWnORuQR$V7x&J#k{ zr(L)K3CM47fc}+4h0ye^0Y^(0m#Drl{!MKHSq#~_s57Ox!a5+ZFU&o3a;fWtV5gT= zFP~5fzo19UuT%^5r%Z5uow)VX--VQ{>uyoZZm2P?Dqb>@o@k@fkfsD!pn0h1zW5@w z0K=D4X^a?wTvzu+^dCWfM-d(@bcT!E)^hUGv1}BNAu@~I_kP?%^FQEFirPUq;i$8M zmqMQ8E9cN@0*iPi7BTz=^MLSNQ5O=|mm=`}P?Iz)teZu%_$fP{+w7BDN}LaTKkSJM zbt_zMCh^C!{KG({nL()Bc(QtxhJ{jLs2G4DB{D$maW03w{796`AJ!uPAB{;Gq?k56u$1`*EG)v*ieXA;|7MgqIXJpcPg6z+SVuWI1xGqNU)kD@$XfsUygcB?8VNP+ zpsfI+CM<(&xXeAo z@*gN%q_dM!-6t9!va25<1JKEFPnE`@4;#dht1x!;OUD;G!>~mMUvGZ5KFH-m%BMrO z?$#BjP6Udb{|*-7C6W z?20U-{c_6re6N_9n3z^*K!4LhLPFF_t))}F*WQEG93k|fNul`*GpG6CTnI zI^zC;BByJi9HklxvW3s-7QhpO-QlK3)3Ix_c04*TBfWwtE4%xo1dd#N)|VT-96Bvc zdM5j&4$*^;OMn}twEQ^a?J8Gzc*0sbw>$Cm&LwH#9WbTl44H15Mna*E9Jo?}gaAl5 z>d{NqE!qCrMa8ruUf7yz>2weIurXOORC9b~o^3R4co6&}YI+=16VD2)CQf6ImgLF1Kt@OgCji(>#}TDI>mW(oi4Z_1 z*%ui3E0>s=gV1{dT?%Vho+Cr%!~ekj{ z+O`IUB$$q;41cVx_7>-lVzp*0aShp6@~+CJv<`8#^*By_Ak-C_$cxI6l$bZCr^_ zPV5ur5fUb9VP|Eh2CMtX+V7+!M477yrbt!qjfz|fU|#d%bPNyfx;hhKXIMo?kkA+D zefK>*V0Mgk>yHhMq!j74Nf<#zA@?|DCy1eFjgdmP81rp5L{pY1so=v7c^!y=lJx+d}%`!zw=R@ZFt2RYySf3;)g?Iys~xTlP&h5sv)_d^QA0O-B48 z3sG`Hk&$zcjIk8NK-aB=$yXKa3@s)ePk*V+{ z9xi!BL2AZ?w6`f)W7sp?nz6%}ZXiKf(k~g29eH=h_eiCH$N?8JZOrH%c92~NB?U9KGV3EA2-P8Tj%aUFsv^n^f498P#k35qW{b>9-SDl*eNf#7RWmECC`Zu&wJ z0X@C3DGd@$K00d$&S%yXyx71*%ouF3eX>F6IQKb@T18M$X>}83N)%!WMITfQqZ{1< z)7z(>-ML{t-(=|v_y!@Zh`p?sKD&Tw;+SBeKy*mXQj&1aEkU5a&%5!a;>GU^lRtxU zqe<05)yq`MuFvB<$jB69o2sO_z*dx``OXjT)$gYN5dfIa5=h}R4*m?69Zwqnw#TgO zZE_F*%Gwwlcmhsja6Ws=Xeb8kt4#C=C*XGfGEWUwk;wre3ZPYT{;>tmoLg z6thrZYI7;@_U+rzv9ao!8u1Fvmxx7;@=xPFEhEF!(lUH%O7&0-!%4%k@o~s{Y|%-Mc?30^KoVAM^;yjt0J7q@tLk%LqG)xsPpkW{wO?Xr+G2BwY4VG0G4>Zp_SKPklV@UaPQbU66sbCB!(9b{p+6e|mFk7#B!>Dx3xP27!4gooy8h4A?d%p} zvG^!iBdQOrsvC@3EFXK)YhRz0B7%*32~yimtGMQNHz@q8yPEmMO3d42mmhFA^C)CA zTY0Q%zv)f1jw`k1A)zkkQiD)E@G@-~k8N_Bkf7e(;wwCy8h8Dw2cOEAsvMMF{HJ`T zxp9#p?wfgO{cbQ(w;7<#12u{XT*%DfAT?05G);85vduy(WIG7A`tECoxP?6t z)_6#MA@(84(16(|+SKppnT$u`LRa62e$@SxBa->mBnbA9!)PY3s?aeq+S>RcGH_Ux zLmQU~T0=3-Og9srP|#+m%H^AglGzW0iNfEnRE{p?sC#$&)9&Qmv;9;#gmfIvGPWf?flaCtHH%GrM5N4O+&3gX zuFjyMdV_yZ{C5$*tLDcz^KIfdWa*U{)Yp4++>|v;!(;pJ@1%GpU zeAal9T@J<*`R0IYAkW)8!t07Hl=$;F+sRm48i(=`_%&@=S`!-Gaj6W{p((`5EK*yh zK{`^l`xE??+U8sWVPPGMh9i1}QNqX^`;?~lG|yU-W>sxd-6;0`^-1TOTFyz`mlS0p z%PZrf$T^PhmLP)c0I=J$eB))VbHw2S(ZP2;^HfV4tm)arn;VFW(w|Z*!@RV~KL1 zYt-rsMOH%aSQcWe0V4o#)5!J+1vNgFeAc`rdG@<@$lu{O5<&UE z5o%$N&6=IW^%cbg_#OupnYhxb?l_I3aDR-L2og&&(b?u$YR=(BEw2P^1D2IHxj$Ic z6y0DcpH2QvVgbnqRpkG77O<^Zh$N&RI?x0p1V)v%9~hQ~EY6b|Lwaq}W3g#rkDepj z`1#_noZP9sV}cUv{9*1*fRtH{dPcBJ@KlXu?sUfJ91b?OBre8_v>F@zmW}JZ7wM;LT)OnSin1i!6|b!b zU!!UboxPew&`K=$Wc^ zNzPJ2CJ7}XeDpB9Y8ba{8L%}81PY?1?tdagp_Yhm4J`>iKdLSB+wKu~T&zOs?>Dhq z{Vt}8^48Vq+%8c6tGZd2c253u9*&-xJ>{=Fd{+};>A}fRciA4neJ#WsS2UCB$t-?+ z_1@}4wS9@-8eLx#H5+O}#D5}%i`yn(NP6%)UG~{H7|>k_Yf2Q+waqghS-Y2$TkizQ zb#$M1W6*zYAx!S-vi|MfQZ$(#ci=er0m@ZeCP}!ZQW=DXu z%24{Ji99>Pp2IGxvH&*o5u0e$Hu>&^p-7pA%#u8|GICiMYugfn7|zv_^if0~TUGun zz$_-#9b`fQ3S*tKG3={6WKR37#<%saH0cV0EbEN$b#eIH9gSzqDuo*QdnV9E6~4YM za4{c>9B>_~Z?1|RcW@oNz{=8VzkA(-1k?I2YHGm(9lin_GyU(T4P(eZn)OcX;geqW z8Xc4useiH5$r2elSoT+NaA^;b_=0|yQ~Zlcjq2l6+WYVW$&5QDy9i0ft(8{-aQtKd z+V-+%G-B}8V>XrPPNaz0_MQRw^-E3fIaj8ZGLo%>x|RJenV1rGLTf8Y_KOkuaz{Hh z9*!CqgCWtiImH0`A^BnJ>87jS)dj52l_A^I+dC0dO2|JE>9NtWI4@XT8p&jE;s@e! z+uBtU!#Ky3LpQoT#}s)o`}t>fvnC*l z=(kVG=k{Z{pSnzy#f0+OwLbKn9$6=2c4b`~?A~3#q_7Q?&smFvT1oWZoyjx^ec!m- z=z|$qk+{i3AE`XgIcTGoJhHk->>r}WZ0HwsdD*l>oTB^L{TS7z>%*A>)rQ_*NkxSk zXcCYc@-rd$MNDk*4^mW%XftyNLqzbl#`n|aAXN48R(WL`RP>AoHmX~6E+rYFqMBjN zX+YYoE)`MQIGrlqCN7bQ*8OoEr4VYzLAF=doBU1>JI)%4o0FHO&I!GW>q8c>X&+7C?Km zQ6y;EL~B{V6M>$qx{@0pr;3A`vIVP1i3l^?YMwc@U)QZ)M#q+GZg~NOczOK%mFnB8tb{ij%x}*HW zME^GcSN9G5ry?laRJgX&3lhfjrG_f=R+hN>@{N=gVqRZYf4hq6iAJ7@Y1L~F&y1Ef zR4g!gI=Qw{N3KTd(&j=)mcto~RJEZ=_rpMWMaB7W`phTaP10=dtHai-JMZ}gEo({l z&F?`k$|0{RV@*jfW(6$*#uchAr^i39rKk^L0Ln`XgnG4~PI6E^R~+6e=~Q9Q@Pa^E zOv#R%_PR_quGpKdDwL_oxG6gN6{=-#Li2K$xWcUpA>u;qVw%>qYq-bS1z#VH;H7ki zXv&rm(X4>n|Jzl_PJR1=YAJ5fRYiRHrj;?eO{dC&rkgN_)n7aqJ5Q=MbAR|}csqZu zh`icxMgot<3aCO}0SmtT>P-KfUEQ;9fDG*Wn+X6PU%4}m?g`JvI$B=V&tUx(FbKm%%3OPhMO10Yg$_+3sgC6 zBBNBC35i$87(mH3GBTeHVyhCi7xcu1ct$TaFKk<%#rhIy?K`p; zFn|R~JuDUCvUl{QY$o$Y{w86{LWCUL2I6{`3SgLo(zH{&szS1i_B3;j`il>-R4!To zPOK5d?uB^-`j1HWJ>`RBXxj0Z??=gBSZm?-Q5Mni4>gvUlYJ2E?H&fF{(HoVN-$qE zwN{HKE~*Nh?lrlSSFT+SRA|F*x`ITlX??osnGLuvP?sJ6W8(y!cMHaq110Bg>EoDNqX$2?&O0X#Ui-_dE!;vDF4#j(E?wqy~ zL&kN8Z4*ltD;;ZT9`PlLHopn-VW8KUu)<6b>VhI5y) zWmWq()qWUEfJoR&8JYd~E!X8Yj!Lz&d;VYet}Cm7F|y#xhxbnU|()01hL<%VS5T$_$Y+ zfp*ccVz2s$5ts$n8XScBrNs{>;%C+ILpNKc#6c=WZf&+nLH8Yu5?BVW8&nYcJ#pVc zH6dUVSx6e3P{y1Rc6&tdy!)BBw)VI^et{6Br=VgZ>)oEfgm4)~4>jqQT*;LUBx5Xz z$@3%|lRz22=}7SU*-%6dL!AQbxl)^h?W!9L{!PL!io!fun!g+E#mV5m4drcSzSoQAV!X;Ds#cL^S1mHgE%!0~ zm83#ug3AoA1IQaPR}-a5S}J#5X;lNLmJ?Ds37{-Q%dxT_7R{Lsg`7iaOWZe;lKj#J zl$2raurSXK&ds%x&7U&0{G#Ahec_ksn428|jNAPMbD?QXZ1K?LQVWk?1j|!Pr#KaP z+1s8+i77AndcejD(M|4h!HSCc56KlWOa`)VqF0u!^GpmG<Zqhsh87=;J%qE+htVAWENYG!c_<13j~iOBht;Js>R@Qz~HSET4_yv$#3 zms@xGn{PaCT}GXuT%RT^pd?PI(WbpX&_mDTpQ@`_fme8>*C0{{kEB!`9?*z*huhe-xh~Q z^1U2C)O1iP9N}dn7aro(VRFpvK77jfsrLUN7V z@N5!|JaK5Lnw~zjZo6^z@0NsQ*jbNfI$pmfBua)zveCb>W;MtUQ8kq{8iD&nME)`m zAjg-u`$t%eiikiIUI!3 zG2$mis7`<9h*~TKvJ1R?1%YKzQ?2+2;GwqSw&Cu*y({z*1TLFb7;>=FyCt&N6zr!) zSmVn2S(|w0>5Vq-BaKoAwBQ$>I+K{V^fX@lSDP3B3u|iU1MbK)UEyIStuFf{PU5 zG@+6uX;x;5xzhukqp-7oK>gU1?LIECXY|9WHc^)0wy#G+pU3%UvSC$PKOC#7m;~yI zA5k|`J*OXr8SwmxyMyo-zGWfO;feW#J=Ld}zpaxn%-e**(FLI2)#iq=p3HhwD%a{Z z#0A9*!Z>tPy5AertMf1oa5l-A1t>;UdAq8;=Ai?PqmXM~0%2GHbS^QgVo}#!x7g1e z?fq2G*(HN_p0CO4o#l4Mh?8HY=mZ?|+MuJQWmFQ#;PugDt?cQRf3U80&8oaF8L&Kp z1l1hKb?*m_(|chyK#d1fKp@nHAXY7!g73G4qp*ru0Ecy1w-z6VT$E*N$E<4eB0HT$lE1IN!IWZHWaeOy*6*zxb8cO; z<8CnFvUNcb&?ILR2v8t?M~wdQ2)TN;*P{~AaQK8!@rZf^vjq^a)MIR*NYeo(@ea&& zLdoo82eedz39_O2dc?`p1|AzZUk$alx({t1lsg!1U|RzcWU*QIMMjF~Q_((1CVUgc zBFK$v9D&efJc2@dFPY+OBA81solb$BGPv?=h*ys zI9gLXyHhqK@Ftt-^;b*|o{=6h=A_r#-2~zTz4BGH&QB$w=x#LN0^W|;D03OvVZ$S) z6PDP_^uYGjL5 zM9~GP(_1ij`H|pwFOI$hd|pozQW(7O>NsFg=I6@~pGLRJW(&wfp2~uAkq8^XPp3=^ zA`sP5IrrSJM_Jg}UY}^9PzvF7^-7~eE3i|gO_A5+zp4WWQ|?si9$yzD==?u9iL3$t zZP6RtC}SSsMByn1*_*yKp&T$oL4ROVCL4C%pyUnA`4Mt!-9g2HeG7Cyp%V}1BALj) z`}{t;4J=e7NcwS=Hkjk?{4MjsWoi#=x8KRs2?&PO|aac4W_(bCE#6K+kO)O1qzTOl_q5jWMek@YZ^3itE6gO zs~(fD)~ydu(*>NZ^Q32xnY-1A6T!qjyxm+xk8BC6z<8<{)!&U&lDvoFl9@fbvX- zd%GFMCV!HNY*VvZ_YK8|;=Th+$?qL>Adwjn8?L=4t-N#$!oueTz0d#5m|=dmwOk9S zE8*@B?!*xJ<=hTE z?7jq5_;kYbX(N6S{`YFV5cLW_i!*-#}eUpI3L5vusT3 zgAgoPSk;h}WOaLpVqJF$3v^oB2sjUSLH8$=IWziHAc`JajzwtT7c>`srQ|?3SDps;>ajTdT4z?{_=b6r1*)UBLqpVfHqQfzJzA~Ls6%YuFSYOAFm5H0#_{KyOs8#+vTuu-rRR>7 zNZrm}o1{a>oC{jqOLO(4jB|;K_jB{9w_74QTeJI^GC0?SQo(%hScV}VlD^aFe2glI z-HeE-IT|N&;gpku9mrUZ{bdIMlaU1D#b2^-*B?O#<+}N`nMrh7Eb~Hrw>Fp#61pZl z&1B2%kV2?MYDE-B>&d%+eJ}HU^^u8ph|rZG)pC8?U6~5QXT-A-){U)Ya&omnX-yG6 z_iJf39?b)5pZXa#v;yLnkFc5j_DwPlZS7}?j8qesO16n$MCsod7;~kBAbwyaMex3P z_ID6nEKZ85qTKRI>J?%3Gq4~ddAi{;g+BhN4{7G!=3(@t`&3esdua4HH1s?+Ls>XL z2n>ejB@Si#l-_XU+)y-KX9G4D)6C3@^Sv$>Y3Y^;a2s(dm7`AqCb)A9wc~f!s`!;VsbZmR1%Mw zMrQk~bg9{XWQ7_`U~pk?D4c5xI~>ViINZw(9mWWFCk*LoXtu~IS3^3Esg8?Tv{0R< z|E4w!PyEEMs_T3=WMSy-l1_DhopJJ{x+O0cfxh+!g&M~;;8_3wJ|y3w_8Cl?C-=KN z6Nr`%-pGRzOtY6pT&8>N92sacQ2pBfry)n*BPsB$CpF_O(H`l4PG_7vgO};nCZqzP zFmG820S8jo3w*<-fiUOQ_NAYoO8ThuU>A|tk&lx{f}ML$WAzB;k{?kw$gkV+b5}|UZy&L+xy7CQ-Idx3|;usL6}CB%2K2vNGe`DwQJNL^IJAf8G6Pu0Ui zGV?c`B9XVhs7U_d>cvMY{mHljPpk+w!l{f;Hj;7yW?nxt+HUhdB}a z0e)$Dc?7D=b`ftlrIzsG8+z&DvPkGy{7=4kCVQj{DTz%1Hz)*2-@}mu^n#ECVIlu* z`nPOar9jtW+cX)`E1j{r6=B^>iw-<(D5gdt&B925nw5ooE$f-fLn#ni^cCflC|_hX*bPHRo%ri*0X~u;9j|8 z{h8V|Cm?ypu{C(wIY0Y55RnAq97KEZitiD87cCH9Gfkd@+@QJb-R*H9)M(5Ci38FG z)S$_lqis#YoH-d=*q(E@p3fg!_w{sRe;E9+r$_pYcC$9H!(E0buTTvBel=M;R93}$ zapamI@#PL{KSIs59OE+K^2N1@Nb;K_NV01fZKL{S%`k4gM%SvA+ld3qRe1^Gcr}>f z(h^QKVsKU_j>E`qldts}3S3Bl3&xNodOr))6)p6nB0Hur>5)IGJ0{_ufr6KtL zzS4dD!^%+Ox!cNFmE+qnsR0;bl-64zA?^y|{+GFKj6ls2p;|6uSk7tmW&!*zTKOHa zF7rX2=jmXEYj+`WF3=dpR#zHD(KMl@bX4mur*s|qaiJKioagjEsoo+|(w!TpD z|CtFu;BhP_2}S?*t_M!0(U+?*WS#VEDhGenE&leXAwL!PjfHn14F>y!GV$qS(^iHW z6lwTThW$D8uXZ*pE9d?;qWVmXo}RJ6ro7|>xn4ne2_-DEh=4pkN|9SLSlha+)ax60 zA}woHq%4CE^g9^U1L;3PQUb5JPst?PZjfOnJGrw_Qu?P;JlOw)Fdc~48jR#J&26~X zL}SqY^hkUl(a6ExjH~l^B-<-sT0hVuDQp9P*z%l9Mb=X2b=`eqyg(Q}+n zuF4<41oQiIo$t_^wY*@Id$m|A=^k`MGANur^jmCkQaKk2hvU6ZVSX#}&y3Rte&&LZ zi>_F*%l4`t>K{4Oe>lK=(|`D|6>r^sFY|knrDOs@vRO?${r}N)m0?kLPn(obx+SES z?(T*qmXz-9?)pgzh;(;%NH-|b-Cd$|cL}`f^S|B?`)zlxQ*-7%GxyvR{AqyP|96-j z<61+#fI_jrisWRP0>R{E&r9cS<|e1f$g(Vtn=H6Mj<^>aNE|au_Jy`eRU1>X=o1CL zi)kTAgGQyjOTQcbm%hPt&`A0_z6hc_4L>2UYH)KqaI=*^c@iDeNiH7>KVRPn1Z8ftEm4_Pa*3q7`D5cDM-bk5?Q~m zR5BE77+_Scp1B`*{~5`)^R^z!`O_iolGE=eBkxoI^?$-wpL`;g_~;``ykl z-&=jbN(MyKV_Y6D6FjddN+LsqYMEOIM{A)vD1#pDhu|P znCwja=>;skH^-~|pIO_4Trd(9_UOKnu<>fHv47Im+-9qVh=oLj~JmaHDz`Q@s#*Es9U0kMsS7ChRNrhByBo*-d~fGxqyB^|AnLo7zlpXtK`zJr1m>x3d37 zBtm`tjlm@;*3>_=Z?94xMtf5H&pwBD+19OOn0Uy`b!LD9b?X|$%0r`;l`VTJLoXmSmDzntOAmJ9E-_fOtmZE9WlBkk^M-r}zAlU!ihIGmNLBQ&BcMo;a(7)F`71F zm#LxAJCue^7&e4sq?jd-dfyoZV02)J-gC;VekTB-YTP>T31wKcL)HK66$mWM&gqHG%WRz9EmW>ttRqR=9uH9z#)2) z{kthYM%(&%rmKId%tGbIvw|JEHT?*X&OvxD*Z^glCN?2{X z0b!Phy}MIp@U*T<#fBIli=p}kZ6ZtOPyT0w&AWgQ&oNT$E4zXMx{jP8%+hor@cX*@ zs6u6xa}k_Pw$ogvSS#JU@1CkfLSdj`6OwU?-EHgC|^e~x_u%>Bv-*6;8FU-@J{ z*c6;~p8n7t$~( z{d78ULA_i#d>0Y4@yKGdWd*SOd3ln>E|%&yG~p4nvEXnS`~FGbIfK?n`Yzq>XX!9j z^4cW#Y6<6R0Isb(5S0C2#R$5)XTHI~ll^96m2gqWn+#f~<&;LGswh*1bw;)Ew_32rVbAg2;qViJj_W@xQSl_FOb|Q2_MvABjjZPpTU>wjx2A-j77% z8enL2TqC`x*{aTl{H|E-2luQIqG%eTN?LJ?ctUX6VLM3cj> zDQOx*qbz|cqh@^eAK(tZ{-My)Gr@le#H*_&5c?LC(K)RX^QjD4lZM3L)KjWh4yZvqZ&yne1k1`M#KejF*v;Ov^Cj%mU(PR4J2H)Pn-<-#S==uJiY5Pqrhuspe zDadzL<`b*Vm(#Imm41|V(bC?b2kr9d5)~9A%S(vk44zU6yjrm6>z33xTe>B{tvRo* z5;8@SJnSbcxOxG}wY;x=X4>ofcl~}cDrMgZSiW>Y zA0bOxdI^_6pvN9qevZW0+TJL(E3>M)XMpv!Vmq_jhKW=UG_yc`REk4fK%l3#ZJTxf zX4(8$>1+N)dw{JAStfQ|a6aym$v<)qOWtTQgU|70ZN&1)Nhh5S9za7w>nN}2)4??exr4k#?gKWw2 zX>_0$AtI6~$U(%w7T~AMfiRY-ZwM)^jS;@WpN9q;{&%vmj+3h$Zopko@de9QYl|7@ zRf{WYJI8Oo$lStWrWq`~U&qUmIjbgmMlKIzI~hGd2?Yl|zZ`EdzT5^TK}Js`#8eS@ zk^1huO|tPN#0e6nP4r~9>*inHzejU_$QK6D?NvmrJOcCT3hfEFD79aI0NzYXSPAuw z?l4kD$^jm3VXQ)(1BU(1;kePf2{~poE{9X@Ve%P0 zPEPILTuL*xJ{F7ZGQ%fOzETz~@R{@jp(q5A0`J(E?aq`{%_RhF(*1HWL=Gv(f(QxolI zlVc9KBF-=6wcQFd(V4sN($NoF%d&9|#r?VfYqI1P6FI~e(S@}(P11p8aF{(ZUzn+Z zLgGl9#RaMZ8~*TRS{C4a$xDS&sX=(?Oy^e4@&>riFcBYGumbCp{ZWsWetZ`uIjHcO zLBEzIX9pC>Kv|MoD2p^kC>T!)!-lOXT?dcg3lBFC4;k2Uv6Y8buGZ$Xo&t!X zn_~0Df^t+tp=nLZ6{B`8Z!P}UX=Y$`_^zOJ7}tUGX&+rAsYp(5`%U97vgB}o8I1Lq z3?Op8Es?47KF&u;v@@|QBP0rip>WOn7=I*4%>5?E{HMV70>d=16OG>FdS=3NyTfWx z&!LH4hl=WGv+Ppk_4eQE`VHMy+KIa}liZW=&yAlr3!{wusn^t6Wy?8=4^;tQWqQLu ztfE~bl0aqKnGzLOp}jRIW+v$MFILpYtdH`4hv}(a7TZ4x4?~)p{E$nHp_D2VXqB3A z>a?M>4bekOc2saaS$R}J;!osCDP-k%XA{!wG6qeX_!CLtXB;H$z>BLY%@|IOIoT!N z-LB@+2yc0LKDHm9GOSE2;7@?N@lJw{GOq1rk%A7VNd}PEYS4nap$BUIu%gm=d-m$JT+`!@hdZGdoa(NpEDWhbrsAH2qRv|L?dYlSaWti zzl3e+^*CgZ$3b~C=6iMD5LeW0iX5y5EpPc;6RQ2{g>U}f%ztNyy_jeY$e(G^p6?Mr9jx>wSdJUyN%GyXY&m%3XskwNwZrON85QLZ$$1seFn7(~i73|4(5sF**jPu=-5|%7R^i zL+fBd0-?sSZGIY;sn!tlMOGsPsM~iYkd#CD?a4$lITNBM)_-;6l2(@K$tm`*ZU>X0 zo(UkqhN_F2JeI74YtEhDO}Fk2GZpnLiAc%#?nk+RNNB{OjXsnPF8ahjR*jP2tjuxu zQ#h(zaAWetBr$Rp`!tg3PxUj`rng{ZdWqRm_;^bb+Lili^ZbitW?8_z6#4bX3+k)o-9_@^dq1qSUzW!0z!59oo=?qIL z+P*{}%^0UAvYOet!P}I0!sVm+)%1uaR8%}&5c>Gx`B(pRNZEFHkkm(=Mcw7czZv=M ziEt!AGv&svuobmFkC{jn1&p->E}gx0z`!)RXGmqqvAp>6^PtUxie9(wY~rrYN!uJO zPeS2zR_Jqg!lS>F_+|ws(s6YKD_IGQk`3kmtd!tJu^I}ynwD}(;FM=mVRb0!HioL3 zMdjK^s%fTJ5oMLt9I1tOnYfnfGGOpLHb?P^*`(cey(fo} zj@nEDHr|!lD4?{4QAZ4-M^=D#{>0j*|0cUX|0UrpcXY`GACJ}lw}c3Deh#%85|BAP zOFKt}AP3(31FLCtPr_In@=gn0K196;X(T(7!1H|$zf7ZZLQ{Bo5B3_r)YVt7jBk*R zx2?^Cht1W+)$lwgxo`12R-5bI&A$>csHPIE1=z#fF^U_B3gT}s-<-#NdWhP+*pu%( zGFHU=K61zg||*<~6k+QxlVN`a90l`LsD z#^G#Iud+1Gx(ckk?7Fub=6yFTgpw+6k-L0V1qdyx3FF^eRxctfuAeL(D%*e+AaW3S zHS=f7i;PnRf{`p@5{_HLz_9`c&&tO%_EnJV12N>;Q^X zilvre5`o15=Efbr@gf^LL!5ulonpt5f|%iUE20K-881?XRl^4{rk_3&H9*(n?BR@> zcU`1+PBHf)RjN1K)74VDvP8;pj5PH}VyI8&%w0;>pRaY$p(_c~cY+XW{+%UbjOoHC zxax2n*Ki$KHKCtOjyV8{gmz3K+3e(>>6rT^A3ipT#%8fb-;{aZu)6f0$To~A9u)L& zVXfTM0=^Mw)5DlY@n3S}z%4I&oj1oeaAHpq@X_o; z&Bl03d`1<^pI`IGMJ+uJa7F)`W!%Ul>us`0&AEF(T#NdAlna14gi2GBXAqgH%OOfh zS0X#UfBklLJj=f!qv4Vz!7U3mlgHs$Qu@ zKM3E-n7ai%7T3Dm66bOTkgoWsZPSj1lpegEx47J|k{Rpr&U9!^cE|HPU*$m4X98p` ztIcb;()(LifL1OPIAw*({2u9~S-mK>U!0vGP;!}E#Zd3D`(*SoAfvqbv=esqxA%49 zPr4P&U8lty6;1U=Q-k!UrTBPl&`6{LGvp`#ffhIW@NRUSPw!!%;e^0E3Ze-;)OF)R zgWJ*B=r>F9^h8*+m1)$A>h$#{WbtTMttZd3pS6X72Rh>R=$dMFzJNJF*%mr6I!&30 z>AR3kbl3q1P`o0^N>@3{(1LV7CZgV$USP(I=Rsy+`PMWY|E z{DFP9?jCXekXU8SDg<>Kc!nKtrc^22?*JTNde>MB1-s%)@Ne~MDdXD6L1=IW0siar z+7miwcT9can?p_uGC$jpmhnb(doI8xhSh%uTl8Y~{N*eI*8Gq&QViNBl-3SZ?S(B( z&mNhLB>i?OqC(3Q7xFZ`L*@w6=jtS`n9F zOmccPH)fG|_Q4c!xy@^|s+@bSqaC8&uRf2Y;A!?s_0+PLM2tpFmXj3r5J-Ty%6gJ+7yuga3F?ZXhYC#c%2TNNeFSeZk| zI?h*`bFU+K5?wz9ROB>Lf&LlG;y;{Q8R`fvZh1z4i~V$;E)+age~?21T7vd8jZM-{ z*nU#sSQZN}(xA1}7Q7(Rlz&3G<0ZWRbvBvPVg^~!YoYs)VHyg%z-m+!&;M%QgKyq! zKwo!&FHi`hG7YvlaD)d#>P_OTKNim6UN8 ziOx7}C};Q7dmV@J9p6dgD+g5~WT!tczVECo7Hvt0)LXEz&}qmT-vw8UuC&=HaQN7N z)X{p`m<0COe>@|*D_S^*4tH$G{~ami<5aOYaO#c=kh(pCWTZGG>kYIXWII^|r`4o$ z6S+w`X4X!(jK3>T((4Fpdub{q4~>53%&Z6pVLGZbr03~zqIthp^AyX;uRnpAFr*hV zoRCb&_b|kP!J7L!WRubRw;+g!tP)c;jpJ5HaURgF%(|yJF|%kcw&};z*`LQf{tx5}fk@%GPHvwnW4$GvH)R&y-29z>I-cXv{Z1< zd-w3YpLg7{9uU1}J7|frtF&>d=m#uYztMb9O8D_gA`9^cv4gvC)I-ND&g0Batc`>Z z)Z)hT3C!$+;I!UCLkP~vbvG&)t=FcD)BtBbnS#;^Hnto40?(LPEMtB6viW+L|FP@R zqOyg5_)X7)q^4Euk2P#~UQ)Z)<`pbFXq35-IN|FK;(IXiE^5RG-p!;#<>J)kUS93O zi?F`M+^3Gw;BWOF+jWUW#YISbe12J(r|;q06XX4#+;Y3diua6uCmYSIy>5VIKmfx4 z@@k{aPoAnm(>+o4KT>`oxY=}c)ZI7$%y;{29H`w3ZK6<{_vfoym!3m!v6O$e*dh!x z90So2?&jED7)7H%)oMU9MAV(HccMRr`8ELw^U^}zlJbA??Gew@c#@Ru!G4A^Sz`l4k!bu z%IZgeR5gZ9L#XHll$dYP8u0@uTFe3ZxE+RoC-l18bkTwZQ3*2|%l-4O5n}FKqa{d9 zd%9Tf)?GtiX03F-aJiJI3vT}kVAG>vAZ?DE?-7snFCQPUL;6**m6E=$t{`witY)E4 z@+$_(5}7IgL`LQ>;83?9^t|k*@9Ul8_Te*<2%FNT7(M$>fqrWCUKts77tJ!hfhtf` zBo+ODSAsJAZ5QpbN({4UT2<+vK0NbPMdANUBk~^=Q)UXf@>VNsS6?O;)8n`f*3{k7Qa&jGo#m`X5Lqs7&ME&ID=u5a|UHXMsN(5vg zHt#={JUM{~9=nLUNVG)JlD+A5*EI|9s`2m%`Fb&I^(#en?TQ9%=bFS1U0Mb8!*=y` z(Wg(+bb}58`hwQTtvVu21Xgp$o{XkT3?){zv49xJybNeEXk8yKgqw${H=PQwB(2eOT%<({`p#+~f}Ubnt- zP3BViUOS~_^2u2^#ve{g+O(F+7N`lZ4cz|-NrH6uwIf$8$5-Pd*YJ|eifRL>+>fOP z&2}ExY~QfIIjNns>Td6KqALN-&0j-jTB)h}-R})7e_cpNhkP zSDg;O62FqYWH2pfTqq_sIpz-Ff*zbzxMzED?v1L^8CKVi<-3iem%2r_yVHYo7)#nJ z*7@rdyXxot>~h20mzO}hlgvEI5qs}vV^pHALVT(yb&=WSzk4GUL$y2sH;5cl*8bk{ zy>r1Q$+i%+=cft$m0|U*#JsRP7&`H{iq(?BZX>en^PX>F14LrOaGmCL*uG30nk_qH z;H!ncr5E|;{Ny~l`^GXy@~alqLd1fcL-IV6po*_^X(E3XqH}d zCoX!R1-zYkI|4;VVluaiw3tnH9?3Wzv@28~I9YrcFIN(Lb=DKy;H)AoBnUSBtVN(T z>B_|~>QK*M{8YF+1ZJ_OVObaAt4lTa$~SMbxxOH#T-)iV{p2DAR&_A?k;wMu-gwH9 z#&rj_%V@gX?}_H&gGka2@?_oB^%v}7GhL8`_~9kzaHcz6q~3f9iRcncPlfbWHyhSRTdTgoBoEG4LY%5v>W6PDo}wqA+`td2745Ci!KsP6si3j$!_) zUuwWa)ANMp{p}{XN@PIyJ9wBKkaN zca2^{Tk%IlUQkwA%%wFpNL{mm>#(@>%m=6_5KHio>HJaLRH&Bb8*DxdKaTeHBUTbE zmFBx07}SOiT5QaExy3Qpg|0`bg&G5BWq8&s>bGUzPX~Ov7_ZHV>petftD-+I>>hQl zTAt&iJS)BlI`9SPN@O^huHk@ssBg1zINE5_Jd|hZkw6V$9?lz3YVxPVJn0hCCl)|l zTvl=-;skBOR`MrYx)&nJ!S|xax7mbrSk%Z^#YTr}sW^C|a%x`GV6``D^Ku{G6g{M{ z@-3=!`OvGOWd_3~f3%}R`}*x}&r5CnmP_xDoiX)x_9^@-(*(iZR5HaRYjV@)5<5ol z<}1?&2e#V}vGrP>D%^K@Z9RaIhN=j#OsUxD+|Z6(yVzOa*%cyQtm7NntLrAin`u^`P< zr_A;ewQ1%j7!Y9gm5G~^r9C{(vs$;|@)S{c-aIua0MaC(%0KjIDunwZuS+$B3A|}T zT(ZUWFH+$UZRxWm5veA5C8@x>&H!Rgl~%-M?s(u7u_9gD)fQ1o)~s#J@q#3gi+=&;i^emzH#HHt>Mt?^NKxc(a?z4PP|e5l-e69TcyMjF)BJ>gX6m|^kSg!Dnx2V?%1qtvmKB4$*m#5V@~k>Q=Pbwin3Aq* zz}J~P@Er)5;AsiSrw`)A|57Ey?&zvego~SqT0DRa5%P))GIfDW$nk_GW{YIO0D;C? z0kf>%o&YJ5#}M;pL|}CP@I-DsUh0#s{Ow7YSxvdQzjjJZJ+M&M#xdiENrDhs^<{`)< zY_Jegm3^k^21nuH9|3b8{%$I!w)3&2PYD~8nwje;>}Gr^3)qqp7O1~jt7DD=~^&_5qIuU<$ zR{Zh;Kdkq!^q+q(${mh<@5xu4!haOwK?0xEP)QMsM%d#=n5QSlE*3elN{%O%#C7+i zXx~GM!qPjbwLby_K{)g$n>=H%5Z$$ff78?XH$7@wc=}TUR~{eD{;jUP!&XSt)G0V= zw+MMghhJ)h8LM29l9Kxfqy_iDU0HQ;%b*!Y5i8;B^?R}%$qvc)>RMw7HJu6{Qm;V|5IpL+-?5PM?rx)gZ3u4BHf%no|}sm7onI7|8!CpcZi z-VmzPDZqO%505{{493p%+YWQZ&6?t%(A*IMKZ(Dq+L~NKamH>;!-Ju*#wt(#vaQ(| zoHVCo^Ol}6GjY3>w%0>lqdQ6mBu&WMABL|=m*J0B9$Wk*n8(rdtV5d<7}fg-G(^6R z;=My>GTCo(Dq`dM9O>zXkbGG3T67(bao-SXnb+JlaNRJgk;w2-)gr^DqCQIFwJQtz zu&17GR+_*4-peXCJBD~PfA=XaFj8Xa!hoDU*#WWU7rGGJ(QZ6B&7dz=tAm zi(5j3#7xP5{tH()T{|`(>jqtJk6)0(il9+2ha4xqohEWbJ_3eb9XaxMqmogCVkw>i ziiCW`%oR$&6dfE?VwjRDR8g$rVHAuiDO{;sRPT%Sxmo0AUrVip|MTWIz{xfEM~+BJ zb|8MX-Dlm;ftMv9t21S|;UL+}D{X;1cbUi;A{xELPv(^Qw~AlWg*oS}4(H0%2|V6& zrJ01MrAg85zh=}ZNff=}U?HNq&w%48N!_O?1o!DYrugT;2Y;|tjgnp+l8EG5Vg|C@ zWJH|DtfrfupRBxJc+E(JfX>{2JE>@4xY0!~w*|pR%o*CYlDLB0*pT1h`}G*C^>|r) z6JVAsLUI?f>(W&NK9}_bsFe=3{zG*fO_VrjG@ZzD@p6>O*9>ZWk(8lHHab#qbbPAH zm+GGtgQQxi!W9j0=&=yFkB}ne3f#kEqjATO%?p~T#LqICuB!l@(Y_Q>=Y73gOV{V+ zcqj#Di_A#O%7_suQtsKS(gghK`NZj0{c$9axQ`yn zBf({Y^$Pv_M>cm3oS*G7nPlg(Pu+sB4(58!kGTq0Z(WTS5uO4ywzkyS{B2Qbk;jg+ zaJgnki^1MB1lqvN!H@SEq2uiAk>AFhP4lGNXx~ez4S5h4xVb_&0K*cJE$V&3kH{AY z%xeEIY&M)%##iD~)vvv8@8X~YX7s3y7>&y+^eZU=dd;*>+)S~fz49gck<)AQ{FHeD zo8{22l=HN4a3!AhW|tVsILx9k_a9yui$5OeEUZg!9s!22`;Li9N1=fUU1-{mzI`(T zRUJ(3!{A|2mN4-fCr;w%eJv&V=I0)ifupB1|K^eIS9SACWp>FU#^|ht)C@C-Bg)Kf zv^C5{34&l`jSmH>7b#9QOeKXhJlL}Y-BH^LpO4)K)PDRu@`2I`5!BEK#jjF`Vko+O zzF2YF0PSP~I^08C!J@n>`SxxxIf`x?23=Iv_YJM5qavn5Z28@!tT&$$vk?Z}p zihp0chH6l=+$e@^Y72WhGHE0wH4NQKJQ#JYAGPk(Uj`>zJdN>=NnSRgLdM&G*}4n1?VLSdN7Q`=hVbAxDi#jY5TTs~q&AW*zLz<%P8pq6N3><#se z1AN;X#H4~xf0?w)q|EXO_5azGEfaAjNCZ`xZT|%d&U;zj2)LKNg+ z=dS#)9x=T)3>R$Uq8q^tbbg--EOh_}_RdY)&?;JpOAYcH8=vX+EXfOD~QLLP4V zQfY9EoLg8s5Aw*G3)6A8xOA0^Lt>f`(osV6v>0(=q#&hl{BR&#)!vx!;zwQdrHUra zT;n9rSS-|%P4#9bGl(i$og>q(pcHj4%=ukJnz{CQPIh7t&fE9s-;GzVaJQ(f*%?E< zgJWQuP;biQe(+{9#dpC7=mM>zs^+)B%9k~-OF0Lx> z*(xSvV}kU?^yKpIIZ1pyk!A%wDZgY(m1c?8|2i|?*LYN*@hv1`aOy;7r^W{&K(PEQ z{4Q6x^;QXzP`Yo^zVLS|8XA*3a$fuJ3Ne6xpxoEHkJcK<15|4XrbV~b< zj=o2~rB#{@cL0jmpbr@*iJHs=NA0PpFQk4(EBu>VC;G{GdHw&M<%1E1x^mzzEJesj zYS-`SC3Y(Krc7Pck4>E<{``orwS&X!%2kOoyHcSm!^qEm-?UU6mK@ruX<@qxDe*dm zAg$toC?W4ncdLM0^$MwLDPebljsyON&)XOM&25ab1}M~KDC#|#+vk5wO19}MK4Uca zDSMr`q2dh(wA zOZ%@5dX^%o1)mFX#6hS|^I{)7o=4QRKYg0Dc06^2oCI||ho$eGNJ-0?rKLZdfOu6z zoE^@#$4ArvG=_du3)O z8KX`q%yyv}G>-|tz mc_ADW;`ow_YtpqJ|qSfYC-}7*OU~9B;?bgp3)Ocxqstg z&q|6^3iJCveNIQAt}28>)zC-khsDFtbl2e*r$hv>(dg)_a zaX!(;bA$&P6KW$4M+ty8-xa%pb|li#r^P?h&8QycE$J1RwI*&~nm%6d93M96fMi71 zWPlE8a=V0qoHsY?oO2*zE?bYodU1n=@_~<*72K$aSYg>%+de2A;$)%0nC@sEYC5VV zR;_@d2CfvUNN8WMT!ChtiA|y9Xl-F^|3RVhvz$yxG%Jeue_d`h*#Lvf9$pRrBMA_(GM= z&#f(TXmM+FOiX>iljkddcg{^V4#ZUFx!7lPzAq>9qc$f1~e>Z3?Rq z1gc?aW@h&H<*ujHu(oBBJ%Sc9y;!OC_wEnyu0h4K<)l)bqx}2b9}-c&%jACXu{Z+S zavh*N%Tqq|sPb7A%FZeDUX%x98>4u|b-Z{&WAUOX%1Cj!_n%ABi3Ft_UU50i)Q4o? zR3+3P5pSrp;ob!wE66>XnbU~7!$^yVl1EV@1ee9tynkC{H#&fV4Njn@<_ID*H&9E9 z!bC!xF8cJ0Js^IX8c`v~+CWFgdQ=2-R!RBjfQoY{<&r(CL{rdb>F+VolaP`0*V?&K zrQo9++gA`jGyMgUXKt-2mOP{n5^jIbjqT~3>b8gKItFsHYuDs zp2^F}!!rO?%dOO^-7PQ8**>hSeX|uKcxt>el6<_}fb=PuQL7$!4XkNDWXSP5NK^wI+_e6U(`OSF(kJF&$p|~b!JE|ByPLuR`u=&Y9ber%I8o`;qfEwT76QKqE?3m zX?C%Kzzd$w{?|+&@Pbt*qS#j3m2NmEA6!TYOvL-a8Qg;rp{{ZyNQgFT)Ge z-l&Aa;lndZNF>o2$2UWkLcg~1NSYPM1k}q2@kVl`Iccwz&O{xCD| zUQ{XMCFyo~Pz%(g>MF(ZE5+(s#H@^vvY(}+iY3}(G55jBj|LwW9N%)5*?|xbLf!SX zUBr4@X=jiy5@WZ&N4sc5!<(+-)IWRN)Beuz{!&GRY-6}djRC2z{JGuSQi1A>?H+wl zro@Ra;XJFv>$2ek>|H!e0y+OA?hXB%oLIlgv>#enS%Kzl@#txCALmN%dkMO?ZkSU? zNksgYl3+_pN?a%PSW=6Oomb{oGdbP^MXV0d3OIaR3Nu83lO2B=IXezn=)h?HL!K zo3T+Z46j*`-f23b`520hI2`KEH?!)}PM(PwK_@Q1(r~Ap0gC#S}XM<&s7B`6X7icJ#vEB z#Y8HV8M6&sYlB_Y2(F6}EbtvW&EPxX^FTgAAVOTE-p4B|d_(6Hc$L|9zYVP=iDJB; z&3&1hJ8h?i>cW?o)7SL8_;x>xJ6$&9K1UCJ0D!edFHcV%*pYn6&;Ko~UNZ{C{bg#; z7>=^gkETUKyEjzK^u;a;FaiPsX*oGOt5D%|(btE`cNiF%w@}S)uI#<%GeFeu_V^b_ z^dVB~^&%F?g8p$QiUd?@eYM%aY`)@S+al?l{0TWC6w}Q_KttyF`>-4*)puCUhQMd% ztp1H64M&s%F3kpsY8EQoGASOAI5MY7$x&fhkOu!d?42U&qQ&%m2X1-LNE;@;T*Ta@ zKj%O{5!b+R+{GrI47#V0Ev!@imG#$yO#aa^oTh0p7Q@g_2J?Wm=Jlg=W$$1 z%dB;smL_odfk@zd)^*q1Rgza_p6TS?V(?tyiKODy&(u^MPZ@@R2oDkFP_68vwalaj z6Zj;8AM;ZA#LFCr1|z7&so6Ok#Ym{IpC~n-e-mOIIXq#becY6LnvTfNf8@oMqEfxN zr5RJ8JUpC_%QK{;WnP>IJPjz{lOHbKX&2SXJVwnaa8as*-ovR99IRY<+}Of+z@ou= z1VvC4)p$J)znQ{3*tSK>A8993PbtAjPgVa=*{)5>2sw%f)1l$9DVu^Y{RQEJyzO$* zXil>Iap}3U9==o^^e=G@?f2AL^2Iy+lG^1$(nS$S@t7k?@;F)mF0#-32P=B{w8JunJiN3ah>kXRiiJ(0IKnf{L`GticwE-t~f47iC zhq_MlJZB)tvY3}aYjLqtwB2N(8pY^4pHP;U9Cn0|#UC3;S4FXTt`oj_6GqdqRpFDmySqzt=x1kV*PMT%!L0cnRbSuU!l{&NK<_^o zXrmhEp8y)K^HFun<#%|DZ#J{E^2IY*5<+1TLC{~OJkUR8)SnJN-)&BoC}nz|*cpv- zFY5ms8+#Ym&fVd4W(h?+xL>3lyB{obfES+zBQGy6mOQAo*B7Nso{JLRuE>8Ll82O`|%Vo?l4VV;36{R7#FFa_? zULBt5(f8T+RbGy%Oy(Pr`*L0SPibJ-$Eo@TbCvhpoCuhi`3rZTQ{ zbZqRN;Vcw5$U^-bR4Vp(qib~zh>eNi5D>5>!4Ei=FP12r-intc8x}S+GBO%~Yk4(4z(EW|MCd7bs- zdz=OCq>}1z{b6ZOP(mMK@-?}@V&7ay27M?7+e(S^*qeOOkfY;$yO=4UuoMp8h6Im2 zGi3V~53*hPGUjtOfrhnfYGH}V?KN0Q;2Y|h-{+#$3E*dYZNo(J?knu=T3bohDw&c? zuhn5`UjIC#3eEIr#l`5NkNleqOV_m; z6p*>DcC@#@b8khD0v5EoFY%z5xNSGXP6$alq(2;uI3vafdOTpx$2cedoTpZ-JGITF~y881y`!3ia8NOKFgl4 zb?1*6zE^O+uGwpsZsY4tz6f-?yUIq){>3(ZNOlsHJ7mO$7#>OlXLp=U&>eZ3n+%z5+I= zTCe4Db@L_VAI$abnn+X@LHQ1C`8f#%NP~b`tndQ13bY|g?(?zL!{cHPq*(1&O~BX@z!qDH1pN2n9*L?ZL5|vnyut3vZW%Wz0)S!dD+>de%&w99(>E7Xy z%9kSdSa=pa)(s={3a|sUe#Xr4gT~Ly4G?~XTDrTBjUJt6;n|y3{H~&&7<9YC6NpZ9 zk#Qx(Iqr7M8TRkxS2EtdEo>_XJST02&sY&-M25|qg^TfgFcl{{KZzyi!g0_W$ zTJ1lOAA%t=l)|j{372GT4ZRxagMXagY1`+kNzvT8I(C=@>R*x{9x>1SHlJFd=UBVW z6j1{C-(>;)M@d!`UgcQfTS6zl)z#L^5ypp^)NXT<94K}=UvmQ{FA6_ABg?^>?@eSg zU+MgN9k#iFQjG%np`W%z&z)o~=>0I#b+&tV_ZitJ zse(&G=<01EPieNWn-$muS&Vs!9Eb1wg*zocxAeNvx?=CMM8cKGzC;L|gh&u=Lu1POGIhm*P- zo*twFk&fvcd6h8AX>F`1q*a4lbTQK~&cs6YI^~jyGhO7l{JqhmM8Z53q&A{Sve4Yj zGDX!&CYT_+ANWw9qxnM*Bd?;O>B|O;?BEV=+=)pqllM9}Au&V-;|Sjup9zE}h66M8 zb}2=vWm)Kh;?vH*96K8P-T4M#-fn$%!{&80aZIkMgMmSu0ZWN%9G-Y|eCQ2i^BTw^ z#>S@H6H}6jCavR^GGCNokCF4`2z6tc>^j%SJ7}Xh6?r2+c7VrVnL5dvJBkG0uolxI zX$IS2<6h6u{To!x?smy1(zY8phAMb=;xfL^w+S}cOe#2s?C4^?Oqm%4qy%V;kKYfK zFdh#dJGm9t*kTWvvI4Hi`$MDZ?|xL`oU)`(3%Q9IOuW0t9v3AdgjEcT6lsE|{-o2; zmuHwrybbDVc2ywJ$P!Kaa|4WOOd1m5;vzsZbHSF2RgS26KVUh?x1u$D^0xnuIJ(N5 z68 z3J_0+%;=y`bYQSFF2x(Rn{NrwwHru+-&l{S(GbyHTDag=UyggTH=jm5B(V zHIewJ0}aZpxz+Rshb>Njn5U^fKp9d3H*$4QA6ATe;&UB)9;%JgNB=%m@M9Z374WlA zQBh(1H@S=!>JtK=5L%UsLY^1vB~;CGWi#O7_xDiuUNP@eK+Km2p9P_sP?EgP?!sJM z^fL9E*J?)Xyr|d$c$hz>d+ZqdoGg0EopjuXVIs3UG0-R!NW(Wycm@ejvZXgs(9xA8 zLvvAxr12|l^o}2Tj9xOFVRRgO0d{~h-4CJ29Ii3L)vy*){nHM(3 zlp&+Em&_e$Wlkwyxqr`}$?WKXNcNzv`_k6+aG^xB>FbxRTjGFY0F$7gzp4VD1O>e) z%>`8E(oa)|F5`t-@OZ=V+1t)S&ayCrQKgMxyNL;+BOf?gK6Bkw$5#fhP~GhO_}-yC^i zAa~ndhUb*HPy%XtvGl_^u2YlwNVBRbXJw9RMJUq02cD}m$52hHKHh4tN9vZ$sY6gu z(2*(tN>I?tu2x~4{H|UOirFm-D{g;PXq{WzQbPYf1Ai`nT^ohww%qFZjOI{v)(%MW`n0%h^FDV_P|(Yw04PC0M@up;yc9qYpd=`0Q7HgQP|#vj+dP!H?w>dPW&W4* zlIW!bhyWu&L5p4iP=bPv1 Date: Wed, 10 May 2017 16:04:02 +0200 Subject: [PATCH 04/32] MLmicrocontrast: eliminated SGN() --- rtengine/ipsharpen.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index 7514a7eb4..cb98fe907 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -672,7 +672,7 @@ BENCHFUN for(int row = j + k, n = SQR(2*k+1) - 1; row >= j - k; row--) { for(int offset2 = row * width + i + k; offset2 >= row * width + i - k; offset2--) { - if((LM[offset2] - temp) * SGN(v - LM[offset2]) > 0.f) { + if((LM[offset2] - temp) * (v - LM[offset2]) > 0.f) { temp = intp(0.75f, temp, LM[offset2]); goto breakout; } From 22d00440013aad2e6185aa3839266f592b4cc4ff Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Wed, 10 May 2017 16:21:05 +0200 Subject: [PATCH 05/32] Release notes: PS 4 sub-images supported. --- RELEASE_NOTES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 3e583f6c2..485c2dd45 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -19,7 +19,7 @@ In order to use RawTherapee efficiently you should know that: New features since 5.0: - Pentax Pixel Shift support, to automatically combine sub-images from a Pentax Pixel Shift raw file into one high quality image. -- Support for processing any sub-image from raw formats which support multiple images. +- Support for processing any sub-image from raw formats which support multiple images. Currently up to 4 sub-images supported. - Dynamic Profile Creator to automatically generate per-image custom processing profiles by merging existing processing profiles based on image metadata (Exif). - New command-line executable "rawtherapee-cli(.exe)" to reduce startup time for command-line operations. - HaldCLUT paths are now relative to the HaldCLUT folder as set in Preferences. This enables you to share PP3 files easier. From 76f73346bf9466269cfbe6fe3d2e2c33875e360c Mon Sep 17 00:00:00 2001 From: Floessie Date: Thu, 11 May 2017 15:03:31 +0200 Subject: [PATCH 06/32] Minor corrections - Killed double "Nikon D810" from the list of DCPs - Turned `-o3` into `-O3` --- RELEASE_NOTES.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 485c2dd45..2be72a060 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -44,7 +44,6 @@ New features since 5.0: - NIKON D5600 - NIKON D80 - NIKON D810 - - Nikon D810 - OLYMPUS E-M1MarkII - Panasonic DMC-GX85 @@ -56,7 +55,7 @@ News Relevant to Package Maintainers - Branches "master" and "gtk3" are dead, do not use them. - RawTherapee 5 requires GCC-4.9 or higher, or Clang. - Do not use -ffast-math, it will not make RawTherapee faster but will introduce artifacts. -- Use -o3, it will make RawTherapee faster with no known side-effects. +- Use -O3, it will make RawTherapee faster with no known side-effects. - For stable releases use -DCACHE_NAME_SUFFIX="" - For development builds and release-candidates use -DCACHE_NAME_SUFFIX="5-dev" @@ -64,7 +63,7 @@ News Relevant to Developers --------------------------- - Announce and discuss your plans in GitHub before starting work. - Keep branches small so that completed and working features can be merged into the "dev" branch often, and so that they can be abandoned if they head in the wrong direction. -- Use C++11 +- Use C++11. - Code must be run through astyle. DOCUMENTATION From 1354ea6f9dc197a7a485ca9316e1ade7c40fb9cc Mon Sep 17 00:00:00 2001 From: Hombre Date: Thu, 11 May 2017 20:41:55 +0200 Subject: [PATCH 07/32] Saving a profile only took effect after RT restart (#3869) --- rtengine/profilestore.cc | 21 ++++++++++++++------- rtengine/profilestore.h | 6 ++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/rtengine/profilestore.cc b/rtengine/profilestore.cc index 984ab9423..12c1cca5c 100644 --- a/rtengine/profilestore.cc +++ b/rtengine/profilestore.cc @@ -46,7 +46,7 @@ bool ProfileStore::init (bool loadAll) this->loadAll = loadAll; - if (storeState == STORESTATE_NOTINITIALIZED && loadAll) { + if ((storeState == STORESTATE_NOTINITIALIZED || storeState == STORESTATE_DIRTY) && loadAll) { storeState = STORESTATE_BEINGINITIALIZED; _parseProfiles (); storeState = STORESTATE_INITIALIZED; @@ -85,7 +85,7 @@ ProfileStore::~ProfileStore () * This method will scan the directory tree again and update the profile list. When finished, * the listeners will be called in order to update with the new list */ -void ProfileStore::parseProfiles () +void ProfileStore::parseProfilesOnce () { for (auto listener : listeners) { @@ -100,6 +100,13 @@ void ProfileStore::parseProfiles () } } +void ProfileStore::parseProfiles () +{ + + storeState = STORESTATE_DIRTY; + parseProfilesOnce (); +} + void ProfileStore::_parseProfiles () { // clear loaded profiles @@ -272,7 +279,7 @@ const ProfileStoreEntry* ProfileStore::findEntryFromFullPathU (Glib::ustring pat } if (storeState == STORESTATE_NOTINITIALIZED) { - parseProfiles(); + parseProfilesOnce(); } if (path == DEFPROFILE_INTERNAL || path == DEFPROFILE_DYNAMIC) { @@ -340,7 +347,7 @@ const PartialProfile* ProfileStore::getProfile (Glib::ustring path) { if (storeState == STORESTATE_NOTINITIALIZED) { - parseProfiles(); + parseProfilesOnce(); } const ProfileStoreEntry *pse = findEntryFromFullPath (path); @@ -356,7 +363,7 @@ const PartialProfile* ProfileStore::getProfile (const ProfileStoreEntry* entry) { if (storeState == STORESTATE_NOTINITIALIZED) { - parseProfiles(); + parseProfilesOnce(); } MyMutex::MyLock lock (parseMutex); @@ -387,7 +394,7 @@ const std::vector* ProfileStore::getFileList () { if (storeState == STORESTATE_NOTINITIALIZED) { - parseProfiles(); + parseProfilesOnce(); } parseMutex.lock(); @@ -493,7 +500,7 @@ void ProfileStore::dumpFolderList() PartialProfile *ProfileStore::loadDynamicProfile (const ImageMetaData *im) { if (storeState == STORESTATE_NOTINITIALIZED) { - parseProfiles(); + parseProfilesOnce(); } PartialProfile *ret = new PartialProfile (true, true); diff --git a/rtengine/profilestore.h b/rtengine/profilestore.h index c6627b4c8..372dbfc3b 100644 --- a/rtengine/profilestore.h +++ b/rtengine/profilestore.h @@ -106,6 +106,7 @@ class ProfileStore : public rtengine::NonCopyable, public DynamicProfileRules STORESTATE_LIGHTWEIGHT, STORESTATE_BEINGINITIALIZED, STORESTATE_INITIALIZED, + STORESTATE_DIRTY, STORESTATE_DELETED } StoreState; @@ -153,6 +154,11 @@ private: * if false, only one root directory is expected */ bool parseDir (Glib::ustring& realPath, Glib::ustring& virtualPath, Glib::ustring& currDir, unsigned int parentId, unsigned char level, bool displayLevel0); + /** @brief Will parse the profiles's dir only once. Subsequent call to this function will be ignored unless the profile list has been cleared + */ + void parseProfilesOnce (); + /** @brief Will scan the directory to fill the profile list + */ void _parseProfiles (); void clearFileList (); void clearProfileList (); From 76bab70ccbb02950edd070d467c9099ebee435d5 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sat, 13 May 2017 01:12:00 +0200 Subject: [PATCH 08/32] Bugfix of 'Usage' text and updated manpage --- doc/manpage/rawtherapee.1 | 5 ++++- rtgui/main-cli.cc | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/manpage/rawtherapee.1 b/doc/manpage/rawtherapee.1 index 9b2469475..3eaa441d9 100644 --- a/doc/manpage/rawtherapee.1 +++ b/doc/manpage/rawtherapee.1 @@ -21,7 +21,7 @@ RawTherapee - An advanced, cross-platform program for developing raw photos. RawTherapee CLI rawtherapee-cli -c | Convert files in batch with default parameters. rawtherapee-cli -c | Convert files in batch with your own settings. - rawtherapee-cli [-o |-O ] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] -c + rawtherapee-cli [-o |-O ] [-q] [-a] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] -c .SH OPTIONS -c Specify one or more input files. -c must be the last option. @@ -29,6 +29,9 @@ RawTherapee - An advanced, cross-platform program for developing raw photos. Saves output file alongside input file if -o is not specified. -O | Set output file or folder and copy pp3 file into it. Saves output file alongside input file if -O is not specified. + -q Quick Start mode : do not load cached files to speedup start time. + -a Stands for 'all'. When specifying a directory, process all images specified in the + extension list from the options file, even those not actually selected. -s Use the existing sidecar file to build the processing parameters, e.g. for photo.raw there should be a photo.raw.pp3 file in the same folder. If the sidecar file does not exist, neutral values will be used. diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index 91dfc9204..7182af4c5 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -549,9 +549,8 @@ int processLineParams( int argc, char **argv ) std::cout << std::endl; #endif std::cout << "Options:" << std::endl; - std::cout << " " << Glib::path_get_basename(argv[0]) << " [-o |-O ] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] [-f] -c " << std::endl; + std::cout << " " << Glib::path_get_basename(argv[0]) << "[-o |-O ] [-q] [-a] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] [-f] -c " << std::endl; std::cout << std::endl; - std::cout << " -q Quick Start mode : do not load cached files to speedup start time." << std::endl; std::cout << " -c Specify one or more input files or directory." << std::endl; std::cout << " When specifying directories, Rawtherapee will look for images files that comply with the" << std::endl; std::cout << " selected extensions (see also '-a')." << std::endl; @@ -560,8 +559,9 @@ int processLineParams( int argc, char **argv ) std::cout << " Saves output file alongside input file if -o is not specified." << std::endl; std::cout << " -O | Set output file or folder and copy " << pparamsExt << " file into it." << std::endl; std::cout << " Saves output file alongside input file if -O is not specified." << std::endl; - std::cout << " -a stand for 'all'. When specifying a directory, process all images specified in the" << std::endl; - std::cout << " extension list from the options file, even those currently not seleted" << std::endl; + std::cout << " -q Quick Start mode : do not load cached files to speedup start time." << std::endl; + std::cout << " -a Stands for 'all'. When specifying a directory, process all images specified in the" << std::endl; + std::cout << " extension list from the options file, even those not actually selected" << std::endl; std::cout << " -s Use the existing sidecar file to build the processing parameters," << std::endl; std::cout << " e.g. for photo.raw there should be a photo.raw." << pparamsExt << " file in the same folder." << std::endl; std::cout << " If the sidecar file does not exist, neutral values will be used." << std::endl; From 3950bf80d38410c43ecff1af2876158a7b4676d7 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sat, 13 May 2017 01:32:02 +0200 Subject: [PATCH 09/32] Small change to man page and help. --- doc/manpage/rawtherapee.1 | 10 +++++----- rtgui/main-cli.cc | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/manpage/rawtherapee.1 b/doc/manpage/rawtherapee.1 index 3eaa441d9..5e3024a99 100644 --- a/doc/manpage/rawtherapee.1 +++ b/doc/manpage/rawtherapee.1 @@ -19,8 +19,8 @@ RawTherapee - An advanced, cross-platform program for developing raw photos. rawtherapee Start Image Editor with file. RawTherapee CLI - rawtherapee-cli -c | Convert files in batch with default parameters. - rawtherapee-cli -c | Convert files in batch with your own settings. + rawtherapee-cli -c | Convert files in batch using default parameters. + rawtherapee-cli -c | Convert files in batch using your own settings. rawtherapee-cli [-o |-O ] [-q] [-a] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] -c .SH OPTIONS -c Specify one or more input files. @@ -29,9 +29,9 @@ RawTherapee - An advanced, cross-platform program for developing raw photos. Saves output file alongside input file if -o is not specified. -O | Set output file or folder and copy pp3 file into it. Saves output file alongside input file if -O is not specified. - -q Quick Start mode : do not load cached files to speedup start time. - -a Stands for 'all'. When specifying a directory, process all images specified in the - extension list from the options file, even those not actually selected. + -q Quick-start mode. Does not load cached files to speedup start time. + -a Process all supported image file types when specifying a folder, even those + not currently selected in Preferences > File Browser > Parsed Extensions. -s Use the existing sidecar file to build the processing parameters, e.g. for photo.raw there should be a photo.raw.pp3 file in the same folder. If the sidecar file does not exist, neutral values will be used. diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index 7182af4c5..2d5efddb1 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -559,9 +559,9 @@ int processLineParams( int argc, char **argv ) std::cout << " Saves output file alongside input file if -o is not specified." << std::endl; std::cout << " -O | Set output file or folder and copy " << pparamsExt << " file into it." << std::endl; std::cout << " Saves output file alongside input file if -O is not specified." << std::endl; - std::cout << " -q Quick Start mode : do not load cached files to speedup start time." << std::endl; - std::cout << " -a Stands for 'all'. When specifying a directory, process all images specified in the" << std::endl; - std::cout << " extension list from the options file, even those not actually selected" << std::endl; + std::cout << " -q Quick-start mode. Does not load cached files to speedup start time." << std::endl; + std::cout << " -a Process all supported image file types when specifying a folder, even those" << std::endl; + std::cout << " not currently selected in Preferences > File Browser > Parsed Extensions." << std::endl; std::cout << " -s Use the existing sidecar file to build the processing parameters," << std::endl; std::cout << " e.g. for photo.raw there should be a photo.raw." << pparamsExt << " file in the same folder." << std::endl; std::cout << " If the sidecar file does not exist, neutral values will be used." << std::endl; From 3c9bb4cb34e998468968e741831169d6582e9741 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sat, 13 May 2017 16:23:12 +0200 Subject: [PATCH 10/32] Deutsch regenerated --- rtdata/languages/Deutsch | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index 780313bb7..ac0fcc593 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -758,6 +758,7 @@ HISTORY_MSG_471;(Sensor-Matrix)\nFarbinterpolation\nBewegungskorrektur HISTORY_MSG_472;(Sensor-Matrix)\nFarbinterpolation\nWeicher Übergang HISTORY_MSG_473;(Sensor-Matrix)\nFarbinterpolation\nLMMSE für Bewegungs-\nteile verwenden HISTORY_MSG_474;(Sensor-Matrix)\nFarbinterpolation\nFrame-Helligkeit angleichen +HISTORY_MSG_475;(Sensor-Matrix)\nAusgleich pro Kanal HISTORY_NEWSNAPSHOT;Hinzufügen HISTORY_NEWSNAPSHOT_TOOLTIP;Taste: Alt + s HISTORY_SNAPSHOT;Schnappschuss @@ -1747,6 +1748,7 @@ TP_RAW_HD_TOOLTIP;Je niedriger der Wert, umso empfindlicher reagiert\ndie “Hot TP_RAW_HPHD;HPHD TP_RAW_IGV;IGV TP_RAW_IMAGENUM;Unterbild +TP_RAW_IMAGENUM_TOOLTIP;Einige RAW-Formate enthalten mehrere Unterbilder (Pentax Pixel Shift,\nPentax 3-in-1 HDR, Canon Dual Pixel).\n\n> Auswahl des zu verwendenden Unterbildes (nicht bei Pixel Shift).\n\n> Legt das Unterbild für die Bewegungsbereiche bei Pixel Shift fest. TP_RAW_LABEL;Farbinterpolation TP_RAW_LMMSE;LMMSE TP_RAW_LMMSEITERATIONS;LMMSE-Verbesserungsstufen @@ -2182,9 +2184,3 @@ ZOOMPANEL_ZOOMFITSCREEN;An Bildschirm anpassen\nTaste: f ZOOMPANEL_ZOOMIN;Hineinzoomen\nTaste: + ZOOMPANEL_ZOOMOUT;Herauszoomen\nTaste: - -!!!!!!!!!!!!!!!!!!!!!!!!! -! Untranslated keys follow; remove the ! prefix after an entry is translated. -!!!!!!!!!!!!!!!!!!!!!!!!! - -!HISTORY_MSG_475;PS - Equalize channel -!TP_RAW_IMAGENUM_TOOLTIP;Some raw files consist of several sub-images (Pentax Pixel Shift, Pentax 3-in-1 HDR, Canon Dual Pixel).\n\nWhen using any demosaicing method other than Pixel Shift, this selects which sub-image is used.\n\nWhen using the Pixel Shift demosaicing method on a Pixel Shift raw, all sub-images are used, and this selects which sub-image should be used for moving parts. From af7821b21dd5f296c94a938580d8faef669885df Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 13 May 2017 21:09:56 +0200 Subject: [PATCH 11/32] Added 4 Pixel Shift profiles to bundled profiles --- .../Pentax Pixel Shift/PS ISO High.pp3 | 28 +++++++++++++ .../Pentax Pixel Shift/PS ISO Low sharp.pp3 | 42 +++++++++++++++++++ .../Pentax Pixel Shift/PS ISO Medium.pp3 | 27 ++++++++++++ .../Pentax Pixel Shift/PS no motion.pp3 | 26 ++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 rtdata/profiles/Pentax Pixel Shift/PS ISO High.pp3 create mode 100644 rtdata/profiles/Pentax Pixel Shift/PS ISO Low sharp.pp3 create mode 100644 rtdata/profiles/Pentax Pixel Shift/PS ISO Medium.pp3 create mode 100644 rtdata/profiles/Pentax Pixel Shift/PS no motion.pp3 diff --git a/rtdata/profiles/Pentax Pixel Shift/PS ISO High.pp3 b/rtdata/profiles/Pentax Pixel Shift/PS ISO High.pp3 new file mode 100644 index 000000000..647c8cb42 --- /dev/null +++ b/rtdata/profiles/Pentax Pixel Shift/PS ISO High.pp3 @@ -0,0 +1,28 @@ +[Version] +AppVersion=5.0-r1-gtk3-503-g9e1fc78 +Version=326 + +[RAW] +CA=true + +[RAW Bayer] +Method=pixelshift +PixelShiftMotion=0 +PixelShiftMotionCorrection=5 +PixelShiftMotionCorrectionMethod=2 +pixelShiftStddevFactorGreen=5 +pixelShiftStddevFactorRed=5 +pixelShiftStddevFactorBlue=5 +PixelShiftEperIso=2.8999999999999999 +PixelShiftNreadIso=0 +PixelShiftPrnu=1 +PixelShiftSigma=10 +PixelShiftSum=3 +PixelShiftRedBlueWeight=0.69999999999999996 +pixelShiftAutomatic=true +pixelShiftHoleFill=true +pixelShiftGreen=true +pixelShiftBlur=true +pixelShiftSmoothFactor=0.69999999999999996 +pixelShiftLmmse=true +pixelShiftNonGreenCross=false diff --git a/rtdata/profiles/Pentax Pixel Shift/PS ISO Low sharp.pp3 b/rtdata/profiles/Pentax Pixel Shift/PS ISO Low sharp.pp3 new file mode 100644 index 000000000..af4c2f7b0 --- /dev/null +++ b/rtdata/profiles/Pentax Pixel Shift/PS ISO Low sharp.pp3 @@ -0,0 +1,42 @@ +[Version] +AppVersion=5.0-r1-gtk3-503-g9e1fc78 +Version=326 + +[Sharpening] +Enabled=true +Method=rld +DeconvRadius=0.75 +DeconvAmount=75 +DeconvDamping=0 +DeconvIterations=30 + +[SharpenMicro] +Enabled=true +Matrix=false +Strength=20 +Uniformity=50 + +[RAW] +CA=true + +[RAW Bayer] +Method=pixelshift +PixelShiftMotion=0 +PixelShiftMotionCorrection=5 +PixelShiftMotionCorrectionMethod=1 +pixelShiftStddevFactorGreen=5 +pixelShiftStddevFactorRed=5 +pixelShiftStddevFactorBlue=5 +PixelShiftEperIso=0 +PixelShiftNreadIso=0 +PixelShiftPrnu=1 +PixelShiftSigma=1 +PixelShiftSum=3 +PixelShiftRedBlueWeight=0.69999999999999996 +pixelShiftAutomatic=true +pixelShiftHoleFill=true +pixelShiftGreen=true +pixelShiftBlur=true +pixelShiftSmoothFactor=0.69999999999999996 +pixelShiftLmmse=false +pixelShiftNonGreenCross=true diff --git a/rtdata/profiles/Pentax Pixel Shift/PS ISO Medium.pp3 b/rtdata/profiles/Pentax Pixel Shift/PS ISO Medium.pp3 new file mode 100644 index 000000000..5d3cfb7af --- /dev/null +++ b/rtdata/profiles/Pentax Pixel Shift/PS ISO Medium.pp3 @@ -0,0 +1,27 @@ +[Version] +AppVersion=5.0-r1-gtk3-503-g9e1fc78 +Version=326 + +[RAW] +CA=true + +[RAW Bayer] +Method=pixelshift +PixelShiftMotion=0 +PixelShiftMotionCorrection=5 +PixelShiftMotionCorrectionMethod=2 +pixelShiftStddevFactorGreen=5 +pixelShiftStddevFactorRed=5 +pixelShiftStddevFactorBlue=5 +PixelShiftEperIso=2 +PixelShiftNreadIso=0 +PixelShiftPrnu=1 +PixelShiftSigma=5 +PixelShiftSum=3 +PixelShiftRedBlueWeight=0.69999999999999996 +pixelShiftAutomatic=true +pixelShiftHoleFill=true +pixelShiftGreen=true +pixelShiftBlur=true +pixelShiftSmoothFactor=0.69999999999999996 +pixelShiftNonGreenCross=true diff --git a/rtdata/profiles/Pentax Pixel Shift/PS no motion.pp3 b/rtdata/profiles/Pentax Pixel Shift/PS no motion.pp3 new file mode 100644 index 000000000..8dc1f73b3 --- /dev/null +++ b/rtdata/profiles/Pentax Pixel Shift/PS no motion.pp3 @@ -0,0 +1,26 @@ +[Version] +AppVersion=5.0-r1-gtk3-503-g9e1fc78 +Version=326 + +[Sharpening] +Enabled=true +Method=rld +DeconvRadius=0.75 +DeconvAmount=75 +DeconvDamping=0 +DeconvIterations=30 + +[SharpenMicro] +Enabled=true +Matrix=false +Strength=20 +Uniformity=50 + +[RAW] +CA=true + +[RAW Bayer] +Method=pixelshift +PixelShiftMotion=0 +PixelShiftMotionCorrection=5 +PixelShiftMotionCorrectionMethod=0 From 435f5d979c5f00f5a0e1a9080f6ce17184511d16 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sun, 14 May 2017 12:36:19 +0200 Subject: [PATCH 12/32] Override system camcons.json raw_crop with one from users camconst.json, fixes #3873 --- rtengine/camconst.cc | 13 +++++++++++++ rtengine/camconst.h | 1 + 2 files changed, 14 insertions(+) diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index 5a155e051..2449a1cd1 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -418,6 +418,18 @@ CameraConst::update_Levels(const CameraConst *other) // } } +void +CameraConst::update_Crop(CameraConst *other) +{ + if (!other) { + return; + } + + if (other->has_rawCrop()) { + other->get_rawCrop(raw_crop[0], raw_crop[1], raw_crop[2], raw_crop[3]); + } +} + bool CameraConst::get_Levels(struct camera_const_levels & lvl, int bw, int iso, float fnumber) { @@ -668,6 +680,7 @@ CameraConstantsStore::parse_camera_constants_file(Glib::ustring filename_) existingcc->update_dcrawMatrix(cc->get_dcrawMatrix()); // deleting all the existing levels, replaced by the new ones existingcc->update_Levels(cc); + existingcc->update_Crop(cc); if (settings->verbose) { printf("Merging camera constants for \"%s\"\n", make_model.c_str()); diff --git a/rtengine/camconst.h b/rtengine/camconst.h index b57c3fee9..713936bf8 100644 --- a/rtengine/camconst.h +++ b/rtengine/camconst.h @@ -43,6 +43,7 @@ public: int get_BlackLevel(int idx, int iso_speed); int get_WhiteLevel(int idx, int iso_speed, float fnumber); void update_Levels(const CameraConst *other); + void update_Crop(CameraConst *other); }; class CameraConstantsStore From 4b476d7c6a801bed8da232437b9cdf7fe771c41b Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sun, 14 May 2017 13:08:43 +0200 Subject: [PATCH 13/32] Renamed and fixed line endings in Pentax Pixel Shift profiles. --- .../Pentax Pixel Shift/PS ISO High.pp3 | 56 ++++++------- .../{PS ISO Low sharp.pp3 => PS ISO Low.pp3} | 84 +++++++++---------- .../Pentax Pixel Shift/PS ISO Medium.pp3 | 52 ++++++------ .../{PS no motion.pp3 => PS No Motion.pp3} | 52 ++++++------ 4 files changed, 122 insertions(+), 122 deletions(-) rename rtdata/profiles/Pentax Pixel Shift/{PS ISO Low sharp.pp3 => PS ISO Low.pp3} (94%) rename rtdata/profiles/Pentax Pixel Shift/{PS no motion.pp3 => PS No Motion.pp3} (93%) diff --git a/rtdata/profiles/Pentax Pixel Shift/PS ISO High.pp3 b/rtdata/profiles/Pentax Pixel Shift/PS ISO High.pp3 index 647c8cb42..2c9927e93 100644 --- a/rtdata/profiles/Pentax Pixel Shift/PS ISO High.pp3 +++ b/rtdata/profiles/Pentax Pixel Shift/PS ISO High.pp3 @@ -1,28 +1,28 @@ -[Version] -AppVersion=5.0-r1-gtk3-503-g9e1fc78 -Version=326 - -[RAW] -CA=true - -[RAW Bayer] -Method=pixelshift -PixelShiftMotion=0 -PixelShiftMotionCorrection=5 -PixelShiftMotionCorrectionMethod=2 -pixelShiftStddevFactorGreen=5 -pixelShiftStddevFactorRed=5 -pixelShiftStddevFactorBlue=5 -PixelShiftEperIso=2.8999999999999999 -PixelShiftNreadIso=0 -PixelShiftPrnu=1 -PixelShiftSigma=10 -PixelShiftSum=3 -PixelShiftRedBlueWeight=0.69999999999999996 -pixelShiftAutomatic=true -pixelShiftHoleFill=true -pixelShiftGreen=true -pixelShiftBlur=true -pixelShiftSmoothFactor=0.69999999999999996 -pixelShiftLmmse=true -pixelShiftNonGreenCross=false +[Version] +AppVersion=5.0-r1-gtk3-503-g9e1fc78 +Version=326 + +[RAW] +CA=true + +[RAW Bayer] +Method=pixelshift +PixelShiftMotion=0 +PixelShiftMotionCorrection=5 +PixelShiftMotionCorrectionMethod=2 +pixelShiftStddevFactorGreen=5 +pixelShiftStddevFactorRed=5 +pixelShiftStddevFactorBlue=5 +PixelShiftEperIso=2.8999999999999999 +PixelShiftNreadIso=0 +PixelShiftPrnu=1 +PixelShiftSigma=10 +PixelShiftSum=3 +PixelShiftRedBlueWeight=0.69999999999999996 +pixelShiftAutomatic=true +pixelShiftHoleFill=true +pixelShiftGreen=true +pixelShiftBlur=true +pixelShiftSmoothFactor=0.69999999999999996 +pixelShiftLmmse=true +pixelShiftNonGreenCross=false diff --git a/rtdata/profiles/Pentax Pixel Shift/PS ISO Low sharp.pp3 b/rtdata/profiles/Pentax Pixel Shift/PS ISO Low.pp3 similarity index 94% rename from rtdata/profiles/Pentax Pixel Shift/PS ISO Low sharp.pp3 rename to rtdata/profiles/Pentax Pixel Shift/PS ISO Low.pp3 index af4c2f7b0..cbf2e6c74 100644 --- a/rtdata/profiles/Pentax Pixel Shift/PS ISO Low sharp.pp3 +++ b/rtdata/profiles/Pentax Pixel Shift/PS ISO Low.pp3 @@ -1,42 +1,42 @@ -[Version] -AppVersion=5.0-r1-gtk3-503-g9e1fc78 -Version=326 - -[Sharpening] -Enabled=true -Method=rld -DeconvRadius=0.75 -DeconvAmount=75 -DeconvDamping=0 -DeconvIterations=30 - -[SharpenMicro] -Enabled=true -Matrix=false -Strength=20 -Uniformity=50 - -[RAW] -CA=true - -[RAW Bayer] -Method=pixelshift -PixelShiftMotion=0 -PixelShiftMotionCorrection=5 -PixelShiftMotionCorrectionMethod=1 -pixelShiftStddevFactorGreen=5 -pixelShiftStddevFactorRed=5 -pixelShiftStddevFactorBlue=5 -PixelShiftEperIso=0 -PixelShiftNreadIso=0 -PixelShiftPrnu=1 -PixelShiftSigma=1 -PixelShiftSum=3 -PixelShiftRedBlueWeight=0.69999999999999996 -pixelShiftAutomatic=true -pixelShiftHoleFill=true -pixelShiftGreen=true -pixelShiftBlur=true -pixelShiftSmoothFactor=0.69999999999999996 -pixelShiftLmmse=false -pixelShiftNonGreenCross=true +[Version] +AppVersion=5.0-r1-gtk3-503-g9e1fc78 +Version=326 + +[Sharpening] +Enabled=true +Method=rld +DeconvRadius=0.75 +DeconvAmount=75 +DeconvDamping=0 +DeconvIterations=30 + +[SharpenMicro] +Enabled=true +Matrix=false +Strength=20 +Uniformity=50 + +[RAW] +CA=true + +[RAW Bayer] +Method=pixelshift +PixelShiftMotion=0 +PixelShiftMotionCorrection=5 +PixelShiftMotionCorrectionMethod=1 +pixelShiftStddevFactorGreen=5 +pixelShiftStddevFactorRed=5 +pixelShiftStddevFactorBlue=5 +PixelShiftEperIso=0 +PixelShiftNreadIso=0 +PixelShiftPrnu=1 +PixelShiftSigma=1 +PixelShiftSum=3 +PixelShiftRedBlueWeight=0.69999999999999996 +pixelShiftAutomatic=true +pixelShiftHoleFill=true +pixelShiftGreen=true +pixelShiftBlur=true +pixelShiftSmoothFactor=0.69999999999999996 +pixelShiftLmmse=false +pixelShiftNonGreenCross=true diff --git a/rtdata/profiles/Pentax Pixel Shift/PS ISO Medium.pp3 b/rtdata/profiles/Pentax Pixel Shift/PS ISO Medium.pp3 index 5d3cfb7af..2c83094c2 100644 --- a/rtdata/profiles/Pentax Pixel Shift/PS ISO Medium.pp3 +++ b/rtdata/profiles/Pentax Pixel Shift/PS ISO Medium.pp3 @@ -1,27 +1,27 @@ -[Version] -AppVersion=5.0-r1-gtk3-503-g9e1fc78 -Version=326 +[Version] +AppVersion=5.0-r1-gtk3-503-g9e1fc78 +Version=326 -[RAW] -CA=true - -[RAW Bayer] -Method=pixelshift -PixelShiftMotion=0 -PixelShiftMotionCorrection=5 -PixelShiftMotionCorrectionMethod=2 -pixelShiftStddevFactorGreen=5 -pixelShiftStddevFactorRed=5 -pixelShiftStddevFactorBlue=5 -PixelShiftEperIso=2 -PixelShiftNreadIso=0 -PixelShiftPrnu=1 -PixelShiftSigma=5 -PixelShiftSum=3 -PixelShiftRedBlueWeight=0.69999999999999996 -pixelShiftAutomatic=true -pixelShiftHoleFill=true -pixelShiftGreen=true -pixelShiftBlur=true -pixelShiftSmoothFactor=0.69999999999999996 -pixelShiftNonGreenCross=true +[RAW] +CA=true + +[RAW Bayer] +Method=pixelshift +PixelShiftMotion=0 +PixelShiftMotionCorrection=5 +PixelShiftMotionCorrectionMethod=2 +pixelShiftStddevFactorGreen=5 +pixelShiftStddevFactorRed=5 +pixelShiftStddevFactorBlue=5 +PixelShiftEperIso=2 +PixelShiftNreadIso=0 +PixelShiftPrnu=1 +PixelShiftSigma=5 +PixelShiftSum=3 +PixelShiftRedBlueWeight=0.69999999999999996 +pixelShiftAutomatic=true +pixelShiftHoleFill=true +pixelShiftGreen=true +pixelShiftBlur=true +pixelShiftSmoothFactor=0.69999999999999996 +pixelShiftNonGreenCross=true diff --git a/rtdata/profiles/Pentax Pixel Shift/PS no motion.pp3 b/rtdata/profiles/Pentax Pixel Shift/PS No Motion.pp3 similarity index 93% rename from rtdata/profiles/Pentax Pixel Shift/PS no motion.pp3 rename to rtdata/profiles/Pentax Pixel Shift/PS No Motion.pp3 index 8dc1f73b3..7a73881a1 100644 --- a/rtdata/profiles/Pentax Pixel Shift/PS no motion.pp3 +++ b/rtdata/profiles/Pentax Pixel Shift/PS No Motion.pp3 @@ -1,26 +1,26 @@ -[Version] -AppVersion=5.0-r1-gtk3-503-g9e1fc78 -Version=326 - -[Sharpening] -Enabled=true -Method=rld -DeconvRadius=0.75 -DeconvAmount=75 -DeconvDamping=0 -DeconvIterations=30 - -[SharpenMicro] -Enabled=true -Matrix=false -Strength=20 -Uniformity=50 - -[RAW] -CA=true - -[RAW Bayer] -Method=pixelshift -PixelShiftMotion=0 -PixelShiftMotionCorrection=5 -PixelShiftMotionCorrectionMethod=0 +[Version] +AppVersion=5.0-r1-gtk3-503-g9e1fc78 +Version=326 + +[Sharpening] +Enabled=true +Method=rld +DeconvRadius=0.75 +DeconvAmount=75 +DeconvDamping=0 +DeconvIterations=30 + +[SharpenMicro] +Enabled=true +Matrix=false +Strength=20 +Uniformity=50 + +[RAW] +CA=true + +[RAW Bayer] +Method=pixelshift +PixelShiftMotion=0 +PixelShiftMotionCorrection=5 +PixelShiftMotionCorrectionMethod=0 From c0a1672191fa1a684df4d16fae159d1ce4838eb0 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 15 May 2017 16:27:12 +0200 Subject: [PATCH 14/32] Queue tab Save to folder shortcuts don't update PathFolder in options file. fixes #3301 --- rtgui/batchqueuepanel.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 78f1a8976..af7ab983b 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -103,6 +103,7 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) outdirFolder = Gtk::manage (new MyFileChooserButton (M("PREFERENCES_OUTDIRFOLDER"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); hb3->pack_start (*outdirFolder); outdirFolder->signal_current_folder_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::pathFolderChanged)); + outdirFolder->signal_selection_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::pathFolderChanged)); outdirFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); if (Glib::file_test (options.savePathFolder, Glib::FILE_TEST_IS_DIR)) { From 27eae3474d43137ab4602e555bfc8ae5a52f8438 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 15 May 2017 20:50:53 +0200 Subject: [PATCH 15/32] Use signal_selection_changed() for 'folder' file choosers instead of signal_current_folder_changed() --- rtgui/batchqueuepanel.cc | 1 - rtgui/preferences.cc | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index af7ab983b..3a37996a0 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -102,7 +102,6 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) #else outdirFolder = Gtk::manage (new MyFileChooserButton (M("PREFERENCES_OUTDIRFOLDER"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); hb3->pack_start (*outdirFolder); - outdirFolder->signal_current_folder_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::pathFolderChanged)); outdirFolder->signal_selection_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::pathFolderChanged)); outdirFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index d01d00327..bd5929289 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -518,7 +518,7 @@ Gtk::Widget* Preferences::getProcParamsPanel () mvbpp->pack_start ( *fdf , Gtk::PACK_SHRINK, 4); //dfconn = darkFrameDir->signal_file_set().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); - dfconn = darkFrameDir->signal_current_folder_changed().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); + dfconn = darkFrameDir->signal_selection_changed().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); // FLATFIELD Gtk::Frame* fff = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FLATFIELD")) ); @@ -535,7 +535,7 @@ Gtk::Widget* Preferences::getProcParamsPanel () mvbpp->pack_start ( *fff , Gtk::PACK_SHRINK, 4); //ffconn = flatFieldDir->signal_file_set().connect ( sigc::mem_fun(*this, &Preferences::flatFieldChanged), true); - ffconn = flatFieldDir->signal_current_folder_changed().connect ( sigc::mem_fun(*this, &Preferences::flatFieldChanged), true); + ffconn = flatFieldDir->signal_selection_changed().connect ( sigc::mem_fun(*this, &Preferences::flatFieldChanged), true); //Cluts Dir Gtk::Frame* clutsDirFrame = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FILMSIMULATION")) ); From f23d70fdb2414d529148d04a5ef96facd1c790fe Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Mon, 15 May 2017 20:59:41 +0200 Subject: [PATCH 16/32] Preparing for release 5.1. Updated release notes, splash and default profiles. --- RELEASE_NOTES.txt | 10 ++-- rtdata/images/rt_splash.svg | 29 +++++----- rtdata/images/splash.png | Bin 81929 -> 76484 bytes rtdata/profiles/Default ISO High.pp3 | 76 ++++++++++++++----------- rtdata/profiles/Default ISO Medium.pp3 | 65 ++++++++++++++------- rtdata/profiles/Default.pp3 | 50 +++++++++++----- 6 files changed, 142 insertions(+), 88 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 2be72a060..51dd4c0f3 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,6 +1,6 @@ -RAWTHERAPEE 5.1-RC1 RELEASE NOTES ---------------------------------------- -This is a release candidate for version 5.1. This is not version 5.1 yet. This release is meant for testing in order to enable us to release a stable 5.1. +RAWTHERAPEE 5.1 RELEASE NOTES +----------------------------- +This is RawTherapee 5.1 stable, released on 2017-05-15. RawTherapee provides you with a selection of powerful tools with which you can practice the art of developing raw photos. Be sure to read RawPedia to understand how each tool works so that you may make the most of it. http://rawpedia.rawtherapee.com/ @@ -79,8 +79,8 @@ http://rawpedia.rawtherapee.com/How_to_write_useful_bug_reports LIVE CHAT WITH USERS AND DEVELOPERS -------------------------------------- Network: freenode - Server: chat.freenode.net - Channel #rawtherapee + Server: chat.freenode.net + Channel: #rawtherapee You can use freenode webchat to communicate without installing anything: http://webchat.freenode.net/?randomnick=1&channels=rawtherapee&prompt=1 diff --git a/rtdata/images/rt_splash.svg b/rtdata/images/rt_splash.svg index ab983ad13..bb71a3c4a 100644 --- a/rtdata/images/rt_splash.svg +++ b/rtdata/images/rt_splash.svg @@ -17,7 +17,7 @@ inkscape:version="0.91 r13725" sodipodi:docname="rt_splash.svg" style="enable-background:new" - inkscape:export-filename="/tmp/rt_splash_51rc1.png" + inkscape:export-filename="/tmp/rt_splash_51.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90"> <sodipodi:guide @@ -1001,19 +1001,19 @@ y="2.2370076" id="text3689" sodipodi:linespacing="125%" - transform="matrix(1,0,0.05240778,1,-8.2958692,-4.0353521)"><tspan + transform="matrix(0.91189111,0,0.04779019,0.91189111,15.491783,-6.3327061)"><tspan sodipodi:role="line" id="tspan3691" x="283.85016" y="2.2370076" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:80px;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold'">5</tspan></text> <text - transform="matrix(1,0,0.05240778,1,31.933766,5.1033199)" + transform="matrix(0.91189111,0,0.04779019,0.91189111,52.17683,2.0007677)" sodipodi:linespacing="125%" id="text3662" y="2.2370076" x="283.85016" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:-10px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter5542)" + style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:-10px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4749)" xml:space="preserve"><tspan style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:60px;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';letter-spacing:-10px" y="2.2370076" @@ -1022,10 +1022,11 @@ sodipodi:role="line">.1</tspan></text> <g id="g3712" - transform="translate(0,16)"> + transform="translate(190,16)" + style="fill:#000000"> <text xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:110.00000238%;font-family:sans-serif;text-align:end;letter-spacing:-1px;word-spacing:0px;text-anchor:end;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + style="font-style:normal;font-weight:normal;font-size:40px;line-height:110.00000238%;font-family:sans-serif;text-align:end;letter-spacing:-1px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="559.0896" y="46.61301" id="text3690" @@ -1035,21 +1036,21 @@ id="tspan3692" x="559.0896" y="46.61301" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end" /><tspan + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end;fill:#000000" /><tspan id="tspan3696" sodipodi:role="line" x="558.0896" y="71.363014" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end">candidate 1</tspan></text> + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end;fill:#000000">candidate 1</tspan></text> <text transform="matrix(1,0,0.05240778,1,0,0)" sodipodi:linespacing="110%" id="text3702" y="46.908493" x="556.10699" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:110.00000238%;font-family:sans-serif;text-align:end;letter-spacing:-1px;word-spacing:0px;text-anchor:end;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + style="font-style:normal;font-weight:normal;font-size:40px;line-height:110.00000238%;font-family:sans-serif;text-align:end;letter-spacing:-1px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" xml:space="preserve"><tspan - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end;fill:#000000" y="46.908493" x="555.10699" sodipodi:role="line" diff --git a/rtdata/images/splash.png b/rtdata/images/splash.png index f4f4ab196ac94350d6cfc593d3d55121341a9d97..bad884e4596f5e68f5274e5d92ded8e9c7e5aae5 100644 GIT binary patch delta 51958 zcmXtfQ+Qo%*KX3-R>L+%!^XC4Hn!~<+fKvAwr$(VirH9=_2>QewNKW;JXzOxaBGYw z+z)DC5wga{0LUkkym;xFW~hs)>hd!6yznwLb9HkybFE#0h=g*$_zv}j?1yqg31!C5 zoc#ybF0-+ef5yMjO}fP+LOmXHsrjYIWS{cf{evXd*=u^fM0UE}Z*sa`WOq%Mjlq7P zp{2)bYA$ZD@WPC|PL`LBL`{s0Oq@i?`vTozB;_gY5<ocou55>40-X1xpyc1BQp}1- zzj0|6?}IS}f-2kH;<AT2D|ZC93oZ#4eR=x;QTmJyZp!XW|47MHS)Ry=H?9V4naOD- zZH=O?7J-JAuyu1(&0;(>=gOh6ZIa1%==?y4v_E|Nl+S-Cz^#Mmv)6C57BD|rI|kM> za9TNdCjo|R>@L>TLtgQw8kd%M2uyT#d4dvZUzuc%Fv;37_;ilsn&#NcwhEV%L+Z2h zJ=J7XB?<o_;n3*z#tWWqzDIa^TR7@MA2$s+szRUC71ka&i>PpQwTO^PbzAB!7mj10 zOo!tVYZ7aADnZ3>?eww;<CR!l-cL|pwXWyyUVs)WbNo=(vp-CZR2;2~>ztyefjlsj zZLE{0>c2#$8)uY1P~3j#c3qE+h-JV|6I#@KWcB}DLnRd#GZ;bQaqF~{YS~zYI^1gO znNM_jjZ{aHrrGTjAF@~|$5!xLfxM;+5z&+c8*C4i;gcJLUJuzKl4FMGfa)<UPZ=sm z0|V%py$=lrAZa4D!qAnZUM?EyG8`<npqgs!l`1m#y-tGiyRf19ilo9|Qc(5s27E{* zxg3v=isY_O{%OBHZo|E+ZSggotxd($8X2piY2;X<w>jl@+J`I`$th=8Vf<()9lrNw z7&g+U*S*bZF)>A4oMeKSl+;Kk^Sz;?T?7QxXab|oiGm5=T6SC|O;P?;Hlu7_ZNwvy z`Pel|eG`SeM`CVyVT|qM>(4>S*^6ahd&<e?ot`D^&s^b+$dS~l>EDkG6fm)l-)*n3 z5~jOnUs-}yTtW(RbWt>HR#o!|*GV-N5m>byp*f!2TY`~@f8BhuytWrwd&5mUJOX5? z+KE$LLE5FcNv;{%sV#~0_Pf^uQXBWBx{#EsaPKP2Ly}xo;l$%)TP7M%{*^S*<ndut zit>&MhL~826RbFo>%qmX^=-j9r8)Y>w^R=ozNq1S8j)5g0gIE=dcWOco}Fb(s)Ez5 zo>$KqhN>NaTjebmI||wDG4azgT!3Cd81;8DIJQ;4H5W5-{$jMEvQ|j>^shWlkMxgg zL~oD0!H3Px<XV3&8(A^g>nh^vqJ}I4N*9QDhYx3jqDjR3OI@B;XWa5#n;%kAJAqw6 zNprSFFScHC$@lDIZT;cR6~%^c_TS+$A9qg431LKq++t$+6{$0~1<9r6<p9ZWp=RW( z^KkVR9v~Uux+1Y7UK`D7k5#~1!CLS^qR+_VnKyMjAycO){+nUTJi|7c4y8^ei8AV2 zR9X{!S*2*gfZX$_peKo1jEZY{?qON!v0Kbgt3&vQi&5zOLe`a$UE*OB<zh)%R<ZB! zrMZ6qw|n6OJ63+;rk;|a9`LyZLm^%_USwU)(iMW5rpC3g$&@l&#BdnKimD8qqM`9k z5VSukb%JOMmXgX#flM{TA}>^6qE7y=%*dhPVc=a&J+EOdqOzxvl)53UN;kZ{U-D!r zo`i%gnzNSIMaeB%ilpB^%;B1xev0h7BZ(nDR`^*n$h5Sv?^hRa2l-Gk`P$c$f40?_ zVe~>Ix)>6ecrzw}i>Tc||MvHuhjJQ7Y-QgnaIr`kGeqP%Bh$^Sk`C6q<;s}s8`><x zx5hzMUulwWoyU2&ZuR&5JmB}}mJSh1t<<LU%@$Ftx!5Mn)6P~Y+vC5CmW?9?Nb|a^ zFhE+WzShp^W@Z5Bb+CM%V0})$({e{qMT>lT7;^9_ufOW*djMJ@WYhCy5Rc<g8U=*? zv?^~sJvGHf$=+pY!)NWZSf4APOzW9cg(SDW$7fDGSNUZF5)HrlkIsVuvDL2G`n4^Q zLqzzcT4sww=IKzoLs={RVD(hT;H`4?Ez29q&B}=01+eCpS<*$#k#h&rJ4CDQ{<JIo zlj1jGgLA@`G%H*+2JG#uTo^<3t?#;4`B{|X37oM&fKE0nR_DOqKF+nRwgDxds6P-O z1FK(cSqVMzyHySgva(Ewo9$4C!;i#Y&D=l!(tW%hJFT~yCAGUDfwsZ}!DovYZD3fK zB(<WzkARE#5#P`Vc>lb-PWasoH6qJCD}yM)>uv?fW6we<tilG+k`&bE?@R#uz=Y)} zPaHxrhCRcdjdiZl7m8!4DAd;8gM3K&Gp=AqdV*l)QX#|S#Giya2IPI_{YMNulAVQ5 zi|@l6ElxPY58Vi=$8IhRYNA|=iT~#HIL2wsfNaz2f1H-}HX>dE+PbXqxiW%j>}VN# zi6Z#U&9)7b5VPDg|CT!(zxNi77IP<KG5yxELgRHv9*mS;ph3c|GJcR}n=YsRgCd$s zv)~p}Yohr$J4^n)>z!CkPiOCb3KpLrk|tTUyBH&M7evRgpNt8-PWTEozHS8uy@ZYn z0*j-zAcMj-r8OIK^8X-6(~aZ$G*PhhwF$ih63Tv86|FjxsyI``-w>V4l_%+OTV3>| zFPtDqCBb%Jv(U)j<WK8B@icF*xK-#=dN0Ph*EUsqb0+Lm2~H-}jV;ke$C$KP_vGBM zv<miG)v|;hE1ZFdi)1lKWs&6ko&^!`O&$2t!Afu4*=%VPgg#!ZK8;~i(v-reUR`5f zD_J?~_YM!|z5kGE{~_R_IMeMDxAP23Ts2u=VD!E{NPTaIm#Y|y9tI25fk;61MBPCa zm**IV-Xo#J-P{egYJw#JcQ;hUsDv(M(VU)4pFL;Gt<9eq*CSc0EnaA$C`kfXuY^V7 z_idKZ#z#v_UJb?uqmy6Y$1+=Jaj*ly#T0tGW-vs%k14zaAdLGN&0nY$w$nE^t;NUf z>jh|`{?+B}PJIoK2hYyLs-}6B*0J5(rtC2f>Lns%ysi-e#x^+EqlN7Uc+aU6VL3U5 zO-xfOwdafq29q1{wQ+q_(1Cz<%uS-tk-NQpK#uPr4+_EB#Cs*geX}tySNQLM-l4Jq zGTj7!5xVfsm!bCTq;X~a2EkU7%5#bmXBK{p1h=Cg-B>i>>%H3otvMTpySA1^^NN%J z^*LKzo_foLeL_GaS+Cz8$6atTNluRI2x(la?-clMd6`-X$Y#Xko$f%#8hZTwiHGAZ z*<`Y)uh+JZ^(M<yCx{4c%8Zb-_v<9WQMcH~0Yx-c)&egI-l~(171xHB<oV!$ne9ue zDbj+Qh=q(8n)m)6D97<Z4?{ySZ2B4B8yc23(2DmK8>n3@K2r7?b6aq3#}B=PR&28= z)GOz7Z~A5G8iQfV-T*L77mu}V5*!~Qo*K${d_*-=Vu+b4beS0+ZgCkyZmq64hE(!y z+M_`s_h3-`{qq>>7@FF-ing*r+n_MAxB)cqg`BK@&1xZ}#vkhP5~nyw`U{nB##CCO zeb7pW_HeAjuGeuvRTg}*OogN>jilC}$K6)D+F0;+mp!x?A}(OyeexlmhIB)RE9*3) zzWU}6e|pxfFq~siBw!`pT1Jv>gZI5)WwKs|U-)`nh5a9qZHKJrjJsK~CwY04=6G@7 zfo(1ITso!LyhgggK_6Xm3v$NEF&pODrMBy@6!fp4XS_<}oA?ugtu%|<MwVNG4Nh}i zHX*hyk&1)_0U;pfkBq$rM#VT|sPQ}5T$KJSgEW1X0}@ucaRkk0k*5D$N_-7Fj?wqa zE)1M#<888A`MQgYvquUd{yF-AEPHh5-e-Xo`1o3je54${7u8MOjd6h6Il$|JW2$GH zZwVjLYAv$E{oX-sN-i(O8D-^fHgceT{qgSG$((*E@J7&IVSQG)uFu`gZuqLfYOxXt zmXFHk=WNol&dU&yk(N$<NZ(ju_ch@6SmXW^Ha`gh8gA7rF5zD1H33T{+s9Vq{AW!P ztV-$q<VU*@`s5r@(xH19kGsNuC7O^<$kJt+GmV;d-{33AJ_!SY7W@-Tdv0RY+Nbz= zyr6(VQ(f-kOs;hL0nUQ~ZcB7V$py?sG|Y@L%GGRc=}8klr+cf{{2{pa`bjs(=^b%} zMnyH0fJyqCtVd+^UqJM;$~e+)@*xf_c{xmPm8ea)f=mWWRK{p@XEMIE^01Zl8s5-f z)PiMX;&f+*6>!T+C@q{~1q4-NtNtqavN!-l{4Kxe=l2uP5Jy)>Uy4-XmapmWK+wx^ zxoD~9?t>F}EnFD4Ig^9|i8VzN83*l$jU$az!ZJ9k6~gZyc!dqxHvjEVq-?-Ppv$Q8 za<yd6TvzFN6gS)g=3a6ls*<B_gpW?RL#OMP1G0~-o^ZtpcATf1R=b;e;n*wQJ>Z4Y z_ewXcY@SdikHqHN;J|o?^Wmw8*->1|F;A!rS9#dJfzh2awxu^7i)nb}^Bt(^n<WJ8 zWeLmAf`CTOM~zV0;t~W$gLGJ_W&?xYtI|K7n~;S~2rZ>VXPcdpc%?&(qD|gY%}iIg zH|6uI96POrBpk-Sw^j{nKFGoT7zI2N%Z1Pi_T^fQ=IMhR+uzxwUNQ{+S5l<_?`Vr_ zUnLp7+uUpxhfP>=3yH?jR6NOH0jgYpd6LBUWh2VypQSAatI3>QzVC3pzJIgUyIt5H z&b^}O{EP()Bor+svvwD(rWG@+O{Sue6vXEmPFizF%*9HE<Q2B!URtgJ*U}<9AGa*a zBp4LW9x-2!EDwVx+>`%y$t+9;LhN)fE@6NZA^dk<(9pdg+cZ8Ak<KoAPP)O12615Y zhzmLLL;SwGXtxhf6vx-mnBrY@|G9+I<jhh_U!TWi^*#xU=8R-NrL`XooAz@XjeB1~ zG71$?s5x6qG<3ddgbsj|B(~gZw-h6lHkWrNQbd+c=3zL()*%k`<{&S(tK-(ia1G(k zje-&)1=w`X$5+~7`ur51icvA>-m=D2gCM?AmhxZ53v{+Cgc}m=&JAOaS&iE#E;NLz z&bFKoEKdjY9#AG_Ey3C8h9~g<F2B~5g>K0N>`}ZFJ5WcT3nKzkw41ywJ=Ody!zuA! zh2O9g5)>tQO41aTQFT)Fi*XbBBo&Ve3#1*=VqsFwey#l;7N^!y*Ro(AT{y`|Qd^6z z*^KRUrVF`RoMx*z4&->4rlslPc9?sFLERqaW*Uoe6GBb=jx`_>1}Dai#!UcP9Hh?f z_=nle`A8IVzR?ea>t5z*a8ie0%<CN<sCNx)r;D1uh#6GU|8AI=`sX=zWuLHQr|7D; zWz*r0eO}%MqR$<O`IaXEElnzUl&b5=t6wLTjmpw=h3ypEjXX|KsyzG-pAZ3$+ItAo z<S-n=`?~e8^mya+sqgD$MDfb7{-6sMkSK*v1z3`ajO7AJ-;@->gCx#ysay-R0@2%J z(G_SatGY42XBGS9EGQ^(NE%QOFn50{PU8QdL)$dV&T6i9v-<k<RY1jJPx=exP_#qB zgb#X8c*00;I8-8HW*7t-hB@`rWWK@#-SqXjw7k>DOziE_l+AkkIiWL5q8t{vUf0Me zWw)SD9k5FH75>leTA)7fi1D0QLcIA~w+3P7kKsgJ=nz*?YI{i3IDzrTK5_P3O^7qZ z3YogstW*QX)vDM5N6Qu<NV_<pEjAn1%;E#t_mUFpm&XNjq7yB$QZ9OHEVIa%Lij*H zI83qxT^yBgLC}b-^!^UnZ5IC<m>S6&Xv}@256FzU(_KndTa&FpSCDFlqJTo_z?9?C z<))_uL%Bk4RhQAxLnp{!>l+2L5hJf6PBq#Yc=TW6sZl|PGU;mV**oeU1%<xzaX*~p zcRdi_mX@Xla<wn-(=$=dD>K+1?jxw+tnupSw{y)A>a_{W`ttvU#K<8EztF#DixO&O z251nYgDdIMvDu&SDzF&)I_|#6+O{rb=D+pPUX96Md)~Zwu|f@=6?zaowKCmbZuNh> zKVaqfoS@f7{-B|ON|F%76vWhIE!^!H2#8QsP|3|LP%vEIk!3EgQ&)nO7v$Pg_Eu$~ zk%A*D+@Me!`ov0v3NQtsV)qu=u2i`ifS{_`za{}LqR}4x+fXz-?YE#H;mW7&6)6e| zlhW3K<*jEfJK}eyrc0iYz;?bUR3>)&%;Ql8hg>_BjSZfwzNhLudHFwDd{z2yf;Ah- z37K4THvIG2Hl@l26nvw&PWT>y)u5_%ZIjm+EqMhARlk3~6X`;aUG^){v<3#!fF}!z zYO#Np1S7V>HT;Y|1|jh|mI8w_K#6}F=Jm`Jl<%H$J;C~{d?)s*aAfeA_2t)Ja$lEs z{rmERNvH?7Sp+}!Cvwzg45)q@B!jO@nNy!*Yy9Ws6Dzlw+_I_&KceAo2A~H+jB>WI zF!C}D4Rv{ZHN(Oh53ifMhTepM4{A^o;co8+zaLCw7>!xeD{jt(g3=cbkJEC*Y+bS4 z#vU;{(E|L1{qd0`_3bI@fUl_7i<?$m8SG<aFMX>a?SVpKva15>a@Bj}<6<mqZXu(T z^ea-K!!G>mtqAo|z7@ol2`%2PfIEvD(fSy}TUHo9@cN~8NsZINQj!%Y&K3!`66adP zBoC%1DkS5S?VFFwE$gKwr<G*?`zZYbuCO7)x-dX#O}5GKZlJq2Sljus(WraA)n(2> zjwF3Ec4RP%DoI(<yF1gFOtYJw+m+7y;2%zF{fF?`hHGZ%!v|P8989fI=>*dH_(A!v zeFdY;+-hou%qRH3BlS7p+oO7L9FM+^HmWr|<)4h=mQ;l_z1*pq_bD3|rsWEO^T4-% zi-8Ztivb!w!uW@)gn<c#`X1398@W(_t)^L=T4lGYW}VqdC$e%3{u;e0B&*;#GY?+H zgNs!)t+3S$TmlZ+Mlc~2p6F_%D@X}=K^0sH3$*8*d#Z`XN<9KV#Aw0W9pYq`QZFOT z)1(ybd6DL4lC~j28-kIM2%_+dpGc$ROqJhlinsS(S!mpY&{N%QbD%<p?4>x3dh@;M zV_#Kmj}6q`9OXv#A@jr7GQoqP#=?e<b#U0NC$O}J_({3-hz^01(VK4k&A9Sp<arT$ zac4@id~L2cM8gsQA_cYZ-K(oNrp^_ueOjicHbGcyH{)5|`Mc)<%<VmL26_hR$Bvzi zJ!gZaU#M@7itwIG!Amd+K;T0&I|i;3KbV?V4in`W?47qr^t0H$6~tX6^aaCm^@I-` zkgkM#q9YvEB<QQ+sK@G(kJfU3=y5kQR5sw7{KxSaKL8Y}1U_Y!lW=Fqp`x)b79DVZ zEYS<~m2z{*EW-<Ivr*-ePPM#m#+?48PZAJ5`4VxxexoTnJSpUXE|6`96$&2g#gLKl z4k>KbGuF@31w&=0fn}3$gA35bvaGS3Dew)RG_~BbdtzPL2U%M4X&@~9Q{ZZA@m69b z&uAuE(FB~bxy3p=M<xbMQlc4OYX!?Q$rKd8kl>-+kR6({57V1}GGtlRx_ObVeplg4 z*j5{*rgDEMmf!oZM*jlWT96uCOVi0wVEid9Q<9lJH;#-}Nj_pbXuJ0}+wL)bot1f} z6(!;2fKbr#2ycsq3whsgF05cIVd9i}1=;RR9{`1|mcq$=g%(5T8RuEZPrb~3G`h#> zz_0m|*s9p|bFof&^JT9Jf#;^DE`~&7zA{Qq;N<W|GeNkVO`pC0r^3cBU9WWsBEBz- z$M#SE0<gO~Hi-oN$MXG^nFsr_%bf*e56uX8TthLniMe_hyfIU7Qr&M~d6FX_jS6sa zB7t2YjR9BTnD1Np!^T76wbxV@)!8zLQhYyp$>U^fMm^%|)IQBC`{;kB4qLOiIMa?} zp1uE-|HG3?V$O-u!d=&nFq10*23;mM7t+5ra#B=I&m$Y-4Tybvd8lu-bE`^8c+FXY z>$#d-=I<R78AzPv^`=RHRPq!SR(u`;AbYC{iTY1`vF!p=%<2qrL8|9SXjYT$;eqWI zK{(Lgk$KQr)Y7-dD5nI@PSLUrC^beeXh6tkpUPFSzgb?6sd+}Gr$7m9`G6xBtB@eg zUBN-Hfk;28rGXnbrD4Itl^h_uJb{y&R<B>K-dXzi%y={O|9AGR&rc-RfN_DiZHx36 zkMHR`<-hg6k>h;~wAu8D@rMh;=?HWU$1H`|Wxc>ZpuEFsyV>nr{S_7zt#_a_P)50W z%mAi#u`*&5yu~*rDU-!0k5mehjCJ{}R5gS?RfEwT$;!o@#JtfgMG<aiQG0tln@`J_ z0O@iB{4($6C~GP8QwRMpF#o+{1@)ePy-2OGdlI~LqOjY2TnHZOAT(AF{H_N~yXpK; z{T*Wm<5zpw(r+naX7~tIIeUcwLW3o0s`${v8ui$MMfE?Yv~F6PKd_gEKWwCGGHVk) zsT}TqWQRcqLq+IcD`<4lc$C+paWtpc+ia6ppWj#1zbsCVJP06ZU-k?Zzda})bx-wn ziLZ8_^AWAx?i842IZ$4Fi-jt(%Y0`^p*P6@f_L-Q#u8flzV$u%FA+gX)ANJlVH8xC zMm3~7H3%{N`DGT_S~trM=(0UY5NF&UU}5Iq=Y4}Z-t<7HuZEFH$m1SgfR?-e{F9%J zR3OV`&Hb@)M!@+f&g$A}_<>f(d#tCI51LX-U+Z;IIg((N`|qCSTaL(Y`_LPs49vT$ zYyWzR^TWimzgCugeyah>XM^9!^OIcjD^)(L?N!Uoj_djptSxc1khC3c5pdB)O|}13 zyEyl8Xh|5sH%SBI{_xuAOofBpDS{8rU~8M(UH=m17=WgfEYy7tzXgWoM45HN6M4yZ zxfhMRrJ_`y+5?0Xxj^-l7CP0WuqiriAm7?H7LT27tR={26n73y7?BF2j>Lfjr%ua= zm9)gvXUrEOwguW9HjWv#D97wbVz-%PaGi_y=eO?$!!K?(zxZgZ34dntuv&?yS4uFy z`jFq$0#q&63hRICZFQ1H+FgazW5e(@+1S~n?71j}sVy2khw?r}Hd51n+H7>`fGHI+ zt4RK-VYFFZaZd#cg$^z)4tl(-MiE6N*}lcg0iy9oBesXriAfBrZ<z4QMJ_gL!dEFi ztbwc!o+l23BQh370t;CiZQ+6W#r7u|WTig9X(CYMn?MCRBz}NQF_#h|*`Num(FunW zMcci$SC(tx7GqPVqi$7Z<ChTUac$Bwb2PmRjC;PkQq@4_fUPKb<c#K-Updmtd$Cwm zj^Vxr<5@6|$;8&TeO4@VRSki?YiA@jzUJNs6le{q<GtZ-cP%@Y@p*o$B=qF3tP)Lt z))S3V(tn1c=Rbsj*6Q6GuRKwZzdD^qGh#uq7&=HCN+mlbSA|W`z#vXV?}69T6m)-n zRp;cpLSwTbHhq}k6(sLOpI=Rqr_0`bJ*G|LsC0n_{}LA-=3eF*H62DVG^0vL?H963 zva+c#Pw1y64Qh)jGbma}v1(t$2lSoX9%j`aewf<zXee)LEhf42#X##F2lB?^TJ~~K z3bp7ygF?~@Y3&R*H6+Iof2f<eG{}8ix%yt%AplQ{(&-#YbS1FKBBE%+>J~B)Fj$}r z@j1U$NExzd$@m&8M@J#porzs2V3zz(k}E_d<R?*-NcJin30Kv}Po8}P4D!GJtVQpU z%F7j5D!yDq-)qM!7Oa!{u9xASP3YrR>-5i-X#EbN_ZmLHP}it_CHr8IJzKOo?F+$` zJ^IqRSSyb%?~oZ347HVCNR?pCDMHwJ#m)&t|KxZj{=FU{vXT5>aQy#lAYo1XucqTF zODSJ|D6Q>9t}_n_M_WQ*^sT1e!%%C2?*Urolnj(o8t_K;wD$I<{g|B((Qz8KtIZ%& z%tF+j&Aqg^hlz<pf-hPcu=|H>5@ystoa0#nS0+F?-n!A#L1Ofi{iy!)NEv1ql1<om zWUoi!r8i^#8{&l|LSKO|t3=$sBC7@MwTg5V6D&+XIBE3d9`N|?7Dq_U1{xmvz`?l9 zTJDyx+U%FahM8;LweQrei*uyR`6GMw1qT5uUW9e^kz{3Y?DoTQHe8!I`|LZTW69b^ zWuhG?g1;f52d9b2kBxZNK3dlPi%_ga8Ve6Wj32E_ydq092s&?bt5ej$ql-9RXO$@D zhut53hp&Skrof@LCKS1XRDy$2!Te%k38f)AV{KLT7p&lb-gTYEF^$jt3jWW)Bh|ec z$-pnWD$C2nZ8d@;>vH%u?SiSyiE(7nDJbx`?VM)fzEbURhvJpmNuQ9ns(4yIF0IPf zFc&J5P;*q<dWMMRz)vq+?6CYb4!g-9gapw>Lv%R+E;xw`>fN3A)~QW2Lu~2+peE$U zl^#j(!tv{$S6Zs|4?AI6j27{6w4@Ck@PRXo7&?!U(!OSHr+vdU?yV53dIsk6^zR1` z2szKsg(6JhWG)XuG*Vo-+Gaf!VR7j)jQM$x#dOX(j=w6a^p()1E!ao?yJ#Wlm~<6I z+0MYvyLTHFXD^B0N0iVFmQrOxWcdTnwnK8VoV<6;+Lkb@eBNn$+We?0HD2qZ$E{{I zu~~>ikg^>TrY}4_k9TNj(@U3!ECbX971XdzU{jubLzX5%+Z0oTrpph?W=b~Nmz7<% z+8yn&mW8lXOJKyOP`_36DXWXj{g=x^Hc$X{x=d%Q-Zym(`d)?}pXd>&f6BMLLs>76 z$-<X-JMsNU7hA;F>*Y=A@=4x7QXJ3`#Ij2;(-h$KWZ?C9>L{Nnl0CMj)8a{CUQ(3O zXB_b#Qi7|!ww!2WaD61k25G~bNSP)G@CP~!Rqib$K}zUIrwBwE7B=<;AG5dC1MlBr z&N$_oCBe?Gtv$*0wiim-XC0bSEV#)8E8D?j6pDhAjJ#9W*3xXX6I^aFW8vFf3(1_d zO0Dsr=%&kI!N5qsBt-;OFc8@euG%gi@3hV(T=sN1@flk(#N2ru?RVF?j==(!$d0l{ z!7Mjj0{vprxxKJWUE*+fB78QWfH3{ni;dTH7_E-SAv)Ue^My)MJwZ6JWTdull>J+g zaXsPi^vWf9kTpWR2X}WT@ZbN3BNhMQNSI`7Va!3MX9CZzE=pE~XTtestIH1kV1RYB zcfha9pWovc?t<VMEFToI%4I*ZSm3oD4xY_(r@4mk?Q6lL2i0+P5ul5j`75X{?)&+A z%_BP>EE|MJQOi*OY#?3bIh$RWES&Y)FI_^urPHxixs_R1JCWZTu_|AhV+wxx5(jj6 zd;Ed&P^}*sWXP0mpV~jgPofUBLX5ILFuGLszUEekppsO@Bp(8o<f4>s0x^YM&hB-w z=m+c@Dn<;8!lmA-F#}Q-`2R~V_a=E;l^$Z=_^Wveq>sxp^?yChg)DYI6}}XI$}}TN z=O?Q0G~H|==j4s(7k5zArOPmNHsnm|>)F9{9S<7xAT%XeCt5(w!~~lwwa~TB8$I6- z*@n}Nc_bcB>hGsW0Z1F1StLgDdv&4XmRFt^k8Njjy)>ji{?oPm-=J8RFGF`dG1%_9 z7OuQHldUfH(Jqe}f7&B<@1<`NlNkq0u)7!u&z40+!Cigy5%|4h^DMPwWU9%k2&?lR zd)NAUG`)WNR$x}=6_iPu(MesmP(iAqm~qkj7c~5@zNX$3z*^F_(wKdG;+%+QXZbVm zE6LvW1iA~5>h0WZ-bW+l?JGWBRvNuvR2S7Xx@*#Znd_Q7uM6dFqFTq>y$g4IxdCDJ zL=EP{Gb~&l);DmG6k@PdO;19gBhnRnrYIJVA+~$1??pE*ZTN_wedf*h1kHK=%cAwC z@s=k`qZ?b>YL6cQ)|y7yg3~$uGOK@H19I$K0e-Z<kt=mZ>>oFFR$W&EBFqN4Z?44$ zOW_%~jOT`Q{t;jFL=}l-+F~LNneFS!k_VL5ptb*Vs2aB&vwyOKGWMNAt7<9VzkU6= zAjerNyz&D0#<9Kl_#PrPEj%#sb;R}?#kTA@M{?H!nA4e0U(b^prtom%W4@YA3B!*8 zXV8pjSlO4{LuOY}V<#sgzmw3vNJxv#=z8JRa?PzC{DV$|{wi+CxuOA~Z=Fj^sj~!I zEje)^ZaG!C$9(fbk#b0`8<m(zH)3q0es-ymZbA<n2-WDB#1_x_<b^(SHW|fvxr%o< zdh&&HO9q%?t-45dNTUA4ANu_d7Y9lb0MMS4&(oBs+9fRtZPNZj`VdeVO6fillXq_M zmaoLi1nC?<>!(2_tIFICzi5(9PM%Ms<ka~f@p2=Q`ugrHExAV6{b9wjW$<LVVhtnf z))oJ4oxWZEkSB7?@fdax!DsjpaeP$Yw%q@}W)5shz^4$gX#a4%rDCya0hX7o)K3_@ zx)TDCJi!LJZqd{Jz&ysaxag6ZPWQW5VxbUNtfn7wIfKX^R*w!&1mk{zaRwg3KZ9;9 zd=MVMlMG*D&R^#r*q-hY<}IcPlZUbjIz5!I$l-N)@D$<)K#SnCy$-@5<BJsypUOj3 zZL6SRZppHBI7Omv3G)CS5WZ?V^gNOX)gElOs58opYw_mdOPDhCcD*riWxp`F{cC!U zOqlPEF0jQBxI~-D{eo?dVJir$-1*y$*{k9U<LDDyJS+p-MK4|FNT|62oL1Rcw!tXx zoN1%YTwTPRHcf`dMif(7@dzl2sl)JRaialte<sregt8n3K867-V4$FnYtW4z6K2Rk z{1aZMqrA8C?VWe@2<A<5^v;IW_C$}g)j769&!mmVW}CHg^;RNF%Xp3%9V1S^yUOD| z?Hz}q3f^}0Q8VO?8g9tklp)i|`2cpoJ6@1CS>MdzX9@S|nWs(AC1=}!Q}vYnG$E-u zsX5e|pBgG2_qd}mV9nY{p{N*zR=&XL&g1}3vr`)OGL>n1sG|GUH=f?zQJCzSrS|31 z0k79h-(0z{n{x$fBsy2ZH=!NvN**mq3Q$n9sLDeI_uBhDyKJ&PE3em{iXg*#yO44G z-px3APgwG9k%c80oQY3KSJk=!OY|y~8+SxX7IJTOKx}*kzHeDQw+l!)a8Yml`x3jU zfRR#;ioL)`Kal9nXM5YqahL!ri@8|Rw<Hy~(?!!L6;!5DLTylDs9jA?$YNyZyk3Mi z?47r|D^)I9PpCW}LfGR)zWb&K<>N*et_B{(SdE}xFm5%0pf7H<!%A5HK<H97R^Yb- z-j{0h>bTYqkZZCXWBp9vHXWi&D9?G>D>?C)0&bYO`P(KF0+&{A?~3y=wPS6L%uMwT zLxJK+UbiSzYT*h2i{cpb#DUaD@U^5+EEF2pwSG9VvD`2y!knp~u)<XEK*=ie(a+5F z|0zOaO`aNvdMH1Gvt}l>nENdYqf7BXs5WX!z~A#b)sznJ=*1A+5E~N9=1T0cEEg#^ zUFHP+FXQVvpY_9?@7%cBuwS9TNHux>u2;3_)U-`U`nV}-dd5Gn?30jhbepXOu~Pe` zvKD{_yxZ;&iS2wN)h8^(RD<7qGB~+vf?;T|1On%9e})Z(xmK@VXg}HEjOQZeA)<pD z0`pGiZ1OU6S07XKEH6*x1U^nN#GdAHC`800W9-{j{wT-bKg)aMDv+w1SYL=sl_Twu z>~RW399<Y&xgMQ~3dl5&zYSO3kM|#<ANH9Vd#TuWG$3+nnEVTt^}br6o9<%nza}LW zk(yB~%hP}wd?&Q<;?7J+@J({ZuDAT-0Bq^WGTo<;@7+}_O6gPE<p0O)Y$Ifk#LV)o z>uhYvYy}kVf-=9=J}_C~_jLJ*7y_=jdA7qI(=d{Gt{5gddcDMbf495xiI}a2lZ^$d zTV}UkaTG1WF+8<kB#`0=grY7~=2qx%(JddTmfi^M>1p`-qojSylTp`qB(H@A+~nAF zA(^HJiXXEMrmyojCwIEgkYnx~@;pa`V3|VFu-806B<CEW_8Ehz=Igvad*kPu@5DOC z;(7B4qQOkkw8NkFrl)Sl0iMBH2v*;lH`2@%ZS5RdGhTtc8^h04LwecT*&!=-4H^># zqYb8!0%QIT?nknusszb=u~`UwdeqdMmVu_&iv}90ig_biC5wKlrfwTr;*5;_{EuOR z;n=7Z4osUrq!F04uALrN25kNb0l6+*uboFIdyANRSm>wOb+)Bvg)-~>@5L%@9-sOT zJ32P@<F&F%!~!6!K*)uBO7Bs>rsjta7lv^l?dDRKV;%|zsX_HGy#RKiN&BmJSX1(y zLp5jnJ&&CPc)$p6NuU_l-WnP`L)U2VJWk>eA7o(_BYMI0am;zUwK%+l=z$m&z4}mk z<g`N^7tI+P;h96FV2y_HHcG~?BVvX(dihb>GyJOCo-2x``^8cbp(qM$qi!bi0|n6l zJEnoLL4mN3m4l|V7{Enq)x*Ym?QoGMLN^-vAqq)A`TCmj=<$47R=FC^?Xn7{v#GAT z@#h9<wX}eZb&&e+-+{49rQ)kwme2&UrqtS9qdy)d5K?3>aNpCQ%jlFUZN-K%GcnFE zQmBQ6ZdDT5DL|PSA(a^?G1V2835=P)j^@@-!-Nt_NGTp{MuDJ#LS<CG{r3>=sg8y@ zwuw)3U=vt@liM;}8~6nu|CI8{38@&tPu2E2X0mg2jR%pCgbpvf!$x?rN`PkMxquCW zu6HH|1pmOs%hr&+O(rVZjRWNu9-kBG1{`=56l%+p$c6X|M&aRigVqgj3L%F=<|%7$ zHVEnfND{0vYGBpbJ!PlK=I4j+!T9U4^he5gV>u67Q>4#Z{{pFK1)|ODK%VZJkOW$$ z`(qds3@!b+fv6^<WOHMjp-wE`kA#BCM{-0J+B0HX`(X`!`E0$zRDPyjDQk|}ZaK^Y zgM3^*uJ$ZrAhH%)PtVfn?<{nq6uAEW!52G<W`ccbdVm3e(}Uy~nK{7pnHiCQaH@os zjRiptVqw*W;_;l}XY0dA9FiXri70+zl{6ob8eOLQ`A~}|*?9Ub1yt%fHKyL~)Zm;{ zJH>y-7pV?RVLkAt%SOwPqEI2(i<;f=4+je+jnSc${iH+@-tYt-a<oK*BgONt;zL9` zD=}{00c5wEvEb0ed8cWIr!(idIOo7bp_!57RSbRju|g1AK^(K<#+dQxXUj+!Z_z0B ztfa<6AADyzW9zUu^_`G58jEP7At%d67#9ZDW>)UUY{M)zTVI3u(b?x=(}&z6A%{xB z)FKEg!BmQp$jf`o-iGT4BLkI4tnkeY^MarOkDYb+?)%Yl>#q?UZS^UyOMP3qzb~?I ztmra3>iL5cZ6iX)$LT_)Hw2(Hjr7=l>F7m^(oCWmdnISnj8O!4G>%}H{glOE;!;6c zz^G+3oZAp0AA~eHE?_65e;zAmkW;;G99QKHl_xCL)UsH%I^duxwDE(opQ~llu?Lv| zdhP2Ow%?gRcar%hX6({Z(%-}qykD-bsm-dodUm=V>TE#B%L8r!B9HU@PCJb<&AXW2 z>+W=r<Zhy)A-$xElFrn0$6at}^ZHKT9&XfSS~cV9_p&SWBJAblZ}Jhkr--jayWCDU z2)?cfAvO%GpoC!mPQm?cXihCTXG8uI7@UFp{pAPwPk-!?BK_qT`I>e3rDl;r5UzRn z%uio#lVv>fug#l2!?43mNVjem8&kvGwG${GYfzgVb0;b?ON=erh?zQb1isdOo+X+4 z!%E+BD0Oe@UQB%<glsdDwl}5Ya;PT&3krGN+WeK^So3czue@LOw1=O>V~4z7fG0eW zD8gH^1ZPam<f&1NDPsaTf;3{qB_k<QnWU?vW1ZA?=ECHrZ)(t^DXxJ(URLTl-8#HN zx6c>*BfYfR{6;$Fc768lZ4~C<F4x-%mv~h1^g93?w<x|ei?M#_q3Z6ME1JpUOeJ(g z_*%7@zi^DbY+c_@)oi;Q{&`^003EYHfIL0#_`~rJyfgSyDFqC$=pCGt_n_+ZRCnWf zH0W}d1_bxTyxKPh#G%4yT%1(>1Rmnu(m`X-oC1cOqWVRlSHdq*%L8)_AW^(ww4tG3 zDx;YvI~#E^pO<VV)0B)?^$*tow++p`?w8(4Dke^oKU5OfhCezuwhsRq0dKaM7<C}L zUq<Sj0JOmsExPkJ3hp8}q2^kJ*G`#~{#wn1tpZ6k{~5-_G<H{#P%C5=N0T*rB@sK~ z?XE~xv1hFb`Uc#y>OanmuRdS!e9tgyc|9?yNX?nTPV*{+@2`t7uF|jXMs(Y3$DhvT zq_nG(;Xgg6mA@CIX0nARFt0X279Bwr?J#%4sX8D%Poy)zn>Gk8%`BO#tU9IV6Yt}L z!pyN0svsG=jOJ!IZ>QtU=YADJRSR$ac$cs%U{^T6|Cf85+-c$BK&|vjY>$uc55*Fr zTdcj}^wsRsuS3Hvx=Z}-oG!~8W$B+kW`8m@h|H_0iCRReilSo;0;QCr%mw2D(iKwZ zG~{}m7CV?|xuUr#xaf@qKZM2w#$jc3xD=JiR;TRdnHd*;?ZI4v#s-`R#C;EVaLjfa zpkx^wf2#>0{<oS_mv|C~OK?Ey=p`G3W`b|<K?p6v?a03F_|-!b-DF{+`ug)l{}zUS zsol;cADDbrCK4u)sLBW45EfW$FN4XT<tcDWKrXoP<~fffT;T3vQCPY7Us%LtgCzfF z|3~fPx10x;(CDfUGo5a=t%DU3Y{R&LqbmQ_!q3^*i=B&WH!LxOAbVy|Ti=+9JEo%p zrLI7KYC1y1WTyHd9oINgwRY(5x%_o_G&B5%>r_W_za(I0(rEsdd1ud-?yF0TO;_MX zKeu@}^7a6keL|a?%*jPOn9>#FuC5?5A3O>9TUa2rqyV`tjzF~2fjcbR{14KGpFbP5 zi|1WzNI$2*Cb(m*55+%@q`hxegD-3eA*N-AvE|S^HMj&RZoMYK#oVhMFLHVIF(<V$ zH@m*X9mfOgBdQZ3>t2suiq>A%L6`hxt?nkPf}zCEdXD<Ltl#(CWa(AM6e(^A`=kz4 z>eLHKR6kM7&Lqy-V%efKG;yC;ErD-88rUum*yKhgCIfkid*kei{J0*!*VdV-Ky@&A z#zbOs7*5$ESabXi1-TqYRYyAS`*K!nF?raV`}zJLVoq{z!6?IudRez$4<sToq0;Qc z=bJ@p%INU$_`}!XY5I}nmh5uHlmAXC3)jYLC+ubDer7hJ;iU!_2eN#&t2hQBP1f^* z47BTcqk)rv60sNu*@o?F-&^|~w{}d7*(5=Ue)<SxmlXWTI}W7C#>q3k)Ylu$;`qJ2 zBY=4fS)%rO{#&mFF?U<$!<F{=&sP&v@PWTJZdf5(?x#rSAxierbUnes!_&RX`?hC$ z$;4<ks5tbHQZ}t`<_^-zBl`|#J&TTFTsz$wnjWYGF;VW@r0t0KFQVc+bJb2Km9;GJ z&HwA*hiLTXcZ_Sb(>q@V)njBBv#EYm0Y_U}KFfv(%*IQr(9eBmRs<EDf#(@+#nEk# zd&WBjc+>O0;ZaE``-@pmWQsp3zkKa|s#3FkF8Bq}0~P^)^m2K`UnboP8F;lt_s++# zK<~8m=%9dR!_+`pp_M1|oK-L{uWit*IujGbp>&~bE-u8a)R6o+Da)lsqlpuV3ebMT z{_{gfJ4w1cs%>tn5F}Q?EuIlYOZl-eMNMr3@xumyAoc{Q>9s=g-?gXGjc_ziDXW7B zUb1Uw9rU2%wy}dBNOHs}7#u)k<$Z77z86)}RqHk1(>v(?A*RvRL?sI_C!>_nMc9DY zZyz={4_DPq(M*_av#F{J!U`}T0oN9f0A;s>41Kb}s7T77!~kiX|7h~FL)qk@h6*Hj z<dLJaf)T9`-FHq1ORbO;Z;-#?=dd0uf!NPX+r!h~Gs-}mjL-KIwY=Fu3Rkbm4D))D z`Cwk)g3u()r;!4IXRdW@e(_gr`(u+$NfxbGWto=%K2Szq^WDbRaR+El|LP}f<Tj%e z;%Xd5Dy)sSHWnj4=bEEo%_FJpksC*LIB@h*)z{QsQy>*yH(o2%4g-2qfv5l8AYu+t zOJ#`pV{caj{R&o>3tNq@#2puHjSJyZLFyj)6`n73zr`q?+(Cal+3D(&v+=mJPF}km z3~`QviC`1-i#1#6NB}qalW$#-0;Y={B>W#BI1=%6tivv@#a8($nY$+F2iwRJeGQ8t zS5I&_&oc?Gx(az(a(ereFABBbJ%l|8Po2e!f74WIZlk1WZ8rY%>B|P_uiX*k@-<hg zv=8yNr*FgU%&(a|U4PK%r#pH--+1BTR#FJ}zliZgabF|#0=v#mlevN|vfvZOf~0<E z$GW!ATAl-0&gJ=FXjt_Ba<(B5x`kYfqc-wiENBB`2;xMr$#x@9#r4Yqs;Hb*XRsKt z1l1vxRqvH+iFI9aB0ybvVYFxt1v834RU-GGLRpnT5v+!~hzP<L5%Q}&!9trLY}Zv9 zsu{7&1jBEIfK4tIsH14=OZXf1@7mh32v-x_ossNsu2Cr0JHL3RH)8J(pbf@1r~lnZ znW_pPmhUTqaZ>Y0ARFJrB|;_8ksN$8GjUiex}}MLzmLQ$Vjg<Az|`|_;>*u`OpkgS zc4N4B{+1#4!FJ9yA1p@pu+gfZWpP^nUrH{h2Fc(GP`g~lfr-^^^5V^B=V!^X@Wl*@ zihd0WZ=FAjyf~U!dXY$ubS_xAdQ2R*o6WpM*=6+$`ABVm@t7fL*H!ow4wKoM?v0*h zoCzsbkni?4>Z`n-Fc~4PYZv`!189HCG)PL}Rj?MmJBu2WCG<$Ze@FgVhNeQR5WQZU z;9Y<Xd~2i`Vo)zvC>LskUxcTKAc-I;)2G3bAr~qiDWlYg3mYsYL8j4yl#<wPlT=M! zD8!(lvdOtrNofi(MTBuhyz0><eeDNah_WuR@i!v~V2#(=655A}I0D`hUQvz7R=y>E z>ah_4InSEyGy!6kGz5pEYsZ%}4yK{l%rFn&?q6PT0u{(gJiOqz=UiA}vLl1?snuhd z)}oX7D875>Q+t7{#RPt~7V0MgD{e~<U}}EGO^hVs#3}C#cHZMf5)QSHNCl~R1xNg2 zTI&wJ9_or|No)vjE=^?s@ORe(n-G4Ic~O|$gQbzAPQ)XCQOu7>+P@n5T^AOfr$PZm z{J&q3ntq;~;jhbSH(;gH7*?wfl8iOGGWkAhG3<eIjgiFKuX!=U1oN51xKsUlQH#zU znd8FoX+^!ItgQc5fN!|=rZeH1=tA3qR?>`LF)DQf!wEBl@z_hVYMCT`!(1zouxgFm zaEU!=De4Ko-rL~mx0XJwFz9VJ`?><+vncaR>?}@oqtL^yg!2XJ+1;u1`#)La;KM-! z7iL!Ra$J8;k`{zt#lpf{|Lv<bee|e##lH4X1#}kMq6@Ann>=V_bxB1gW62iMz*$q7 zTvmo+?l$O2onb;6LXr=?>$Z+UUf0JIFZOne<IXAL02dqHyq~EW(to!VA24phJNM>0 z(5vM!CX?qFtzegwC*G>@Oon`YWw{40y)x?7OZQ34@^PDG$0dL9<QZkZhn97s@PRll zRrv=QP0#~*w8niAWZg>WKq)$mf|co<AwT^Ju4oh9-ydoo=?_bWUhrK4ii|mJWQ7_c z5B5hBadbR<2(D<*Q0@$FEzn<QVWeO<(-bRvB_HTcz$Dpk31)KE<@>^6o8LHO-uri@ z%m5mO0Suan&3DiRvw3SRddGmSWW{Fy3D@k!>CYM0fWD!0ix|N%mpM9;xEs<<<#N$e z;Z|oK|EG(|%dtG#wne9-1Ord^2Yrb{BZJ^nGynUAIVigM<1Iaa2dIk+>_ql4{km%t z^Vj>$X}bWkh-;!fR_^vD<96N4ne13Eip@5_7~idMecPHyE~%Eco=b<ffY9S66!Ch~ zc&hW(F?B_0t?|G2mo`z72IxI^6QgXiuKm{iL~ULj_>{2_76cJ*xIv{)%^X~hM6R}* zIo4UR+}FdtPWKkOfT%DwG>LXQDp~>KMFDM(MAr~h?ri@06+Cu-oNRZ?tL)S;!}ZAF zOPDBWJXBIiRa{waS%3(%Dw>Qj!G~ty097C{r5bllP5oI5U|0wnjiQg7E3(Qu#JO|E zLk}G#h#$SgL}QCF%;c~x)cm{YEgDKVLt{AHu@J1%rltr9h-$J7n+uWX8PNZZK#L2* zS!+es7zkmL$!tv5^EJ?101kx+?|?;K_Ug%w{;De!W<*<TR^ZHntkSMZ^Bi|D*|{}; z5gDvs!VxQ;J}$9@ib%q7EJk2)B0uMs2%%lv=Lf%z2t$3)ra{+76`b#(JPxPBvP9E^ z9Byddc}@a=`zz`NAL#>;_knzQ%!c8<%jI=86kgi>PD+US{Of=H`l{I*+`6XoemF>$ z-1x_qH)c+9awv4cKWInTb<z78E}5Oe5774LM9b`9eTAbe`+|RPNq9tpa^rv0Luj=P z)jPvP+qWb8jrK-unbK$P);oPrUansA4j8_D!xjT_`PR36KDK>$u9}GoHcQO#*S!1J z7AH=$p;Gg&CRcHbs`L(UKA!mZcAx6a2|+~s61$*V`#dC9cUKr1tqN&zPW|wxUh~t| zK7Go?cooTBYU(Dp2o3q<ri;plt>$##&W_$;`41O&6J#tmpzC;%w7*}cJG*kVbLm7< z{|sC`e2$GFg5>|XsVhP*Y`m>smkBlhP>E=#@3L~ZsT8n)+m##e0)yLAU@k^|H0G@- zIKtK`PY{y=k^C2VoYoo2#9NE;y^D}3sv;i4l0Sv4#ljUj*v(Ew6}U6<0{*g#8~;$2 z!b->r4-ERhM;5UX^9kI7#Rmq0rTtwg0x-DxZZF}#`nJogkJ5l)bm#`|eEfbE-E2A# zjDodkKnTH<8JzmM&b~f9b7(-bsQq&ELu%H#Sx{BLB8tg;*7c`8iXi<tjQ;#)XFgJV z-IiF;2sOE+Ohh0icbbNpWbKI`$(lkb72jizsqgNu%p;7CQ=&ZkG<R>|i~s?(S>Q^& z17^hd23G5qar%dujwl)G0yw9!D&{z32%l+h5ECmnFIDZf8k5MKLCksPL1m=$+4@q> zzkN6l{?(21GQzkZV#bSV3Y^egyu>e<*R;}dpQ^FqY*2YEBz?5o#WXv_IY6qac4~Su z(I*dnH9h+LX8%>QtTFH}cwkXh7SOs<_;zKBA#G;C;Nl-&u)t&P43jqDA!X+WS1nxK zlIY#~)RHJa`O3%r?8c~oFG9<GtX=W5wl05w%_XBm?T=DvOY@QTEx7r=hx&DEAxv`8 zLCYZAZ)|F^7Wl$ZSyVNZmAL3u?U_~VO`-DEVT~&`QG^XYmR!I0Xb5w&RRPj<wc|s! z?G`OV@w#uXbC+`azP_toS#TXxekcEm)8BO6vKrI$Ul139nl+fq1BAG4%IFNITGKPn zx5=|!8Vn?nZnt&&PK$8}GaoMo^+dmEZo!d1xg=CEw9)C#eX=Lo|5TY>x<*34*~EvY zef&Da>UMX%y<viwpusvI60p{@dxM#{NSe8JPtx7&p0JhkOv}gq=24`LGZHZqp-!1I zH0bHtBiJQ3=s>yZB(vo9IUZsDkBS{QZ%gK0>>9v7KU(2z2u+ExNN4+D2pXZCK~q3e z5p_Y*=+LD2ZeAHLmDCWTg(<eWZ5mA&q4(JU8W@7KKp=su!94|_Z)y?*BIMc$Ug*b& zY}eLS<PmLbINE?P2A<l1jHBPJ5r^R4KQjIapr4`c-+jSzBuShkO>8c*oieBA<4xqv zMw_TGcnTIR`juIX$Kbe4%=Y*Pg{{@w1*(_KD2J+dx;MSWdCo*)&)9L9gfqFOYn66a z{z&cPLh9wzq%aaFZos$POinB)+8vYn|HA|<D16;~){uSfm;s?3vHT7W@P4y4B8$hT z_#|bv6lF0G;v6uU77R0)FU+Ks9>^-}*Z1#x4M#38wvR@px#aE=Zcx#X-<QC?LRkbj z-s;aI>A&~?vvYKwcQAD5w6sTy86(M?fv1V4X`%#VqyCSkuZ)VLYr2i$5ZocS3_iFM z90qrH2=1;OEHHxw7)a3I?(PJFTX1&`5?q5_o_F2vU$51FPOo!%*REZ=>cE`--uDj; zamGA}@9yp4azJsNqqA1HCuc|ZEYvC8*ghU!yzU8+qt*SU{AbK{DbjRBP=GK_z2mTE zquqI_N9^uu_+g^*_`My-(BClfEAN3gheJduqb_d{)c#=Ckgv9?E_}AwieNWwny>d# zL^b!sCP}npknLA!Aoo8&zs@2iV+z8O7l!-ppQ#>UTp~8>quXl!mQihAbBCcK#HLG2 z-^$81|LT7xIJ4cQ#47Mui_HUK#*c17u<IFPMfyT-lxAtGEqBg3k=L&xK}Cxx8g6Xk zzSEISkTSc`C*59$IiBl3;s<tFxX1~ObEL0Gx=20M^im85lY#q@O~U<BUYlt|C|v_7 zlU&Pe%c?+$cD19AAva`Ul*<C0d6-%A{y^RV>gAY%fKRHBvn--SIr9}N2E`+qdz}9T zc>|(;uSz!F$4kWR^<v%9<525E42ylQwO^`z8^u0)_V(mM4gTn>clOa}RD`Vw_JR3m z17)d%ENOMh7l6{Qq=Ia{h{c~Q78dTB-a172GIQD{7%oRY(f8O`YyBglB%w-vk!2qf zT=#B&*vd?!JPU^&eA(c;`?zpg0uT8Aq2DM}-i%X^%BaDUpd<Xwi$Awcu3>*HG{*a8 zgw2q$WTpS7=`+)nRvC+tnM@pKc^KEwX`Y^$+%B*{)_*j`(*TBO9Snl~m`OmUS8rm< z6xT>ik%y8Dn-}Zu9v*;oN1;_E(im`c;1wOcBfVo;ObJsRxG{Ws)q%Ho*3RbWr^DiB z-U|DgsJ!TU`4vnyCVeOZ(T>TA(&=9_DYVT{W%5d!y+wIE{J+z9jd3==e)Y@T){8au z+yElHa&)Mb{$N_mbIEz*Up@>3ZgNA%C<1bmqs<Fn2I)p6^3)zvt3|*_5#~(st%!ta zE=4!Ft;Q#N<ToRy{U&;!PAY;5ITj9c$RZi3E;9PE^Tex->CO%cJJqje<$QKHzh$Ar zSsiKqE38#42u{$HVp@vJ)Hr^uP*Z;U2FSmlDfVXw#(RsVptDc9Fg!57QabDD^kkkj z#Av>6t&jM<0=be@X@-Tf58VKREV9%=J1t>-5#7co@9T^>&4PY+>K;77p*Vae$bF-7 z9_%xKklJ?(mct5F=PifVh=5Cm>f;+btZaC7RMn))G?Ju9mloc!e2s*VI=c2)10I4+ zy8L}m&wX8FXiq`!{7>D0w@1qY)zuZ`j_CSm`owkECHPJDfY|es*x0E_faSCnZIMUT zmpmie6}S2D`ISOd>1zLq<M$9$m%WwQ?o0DD+m!;rB3lO-F@<C8lD`AGxTN!U;l`i4 zlI__6>%l>*SK1@akMg);U{fM@AVC6Zxh}QrTi7|nO)?Udv3YFe1Ibobe-Ul|XVK62 zL?Lf)k15GRtLwENTdfihx<iqa&<!=Im_{m|X)O2K?#(xzf!Pec`i9LGbs8|8^INe- zuW=ziJQSUiMH0kKi#374{f1}|q4&!kdByLy(QC@Nz5!?K0@W9fJvIP(b(C230aPZ} zFbW&0{KnFALyDVkE_IZE8a8he%{yDZ^?Hiucylv`n}GM!>Bl9H$krs(Xqd4t7RF?L zGu4MU0DI|`MIS=ODLjNX9A~y-VxIX^boPkdp4xCcXTFW*V9OiUW&Ai+KE?byLl)7^ z)Q{>@$xO%-!Bz10>I?w9^zWhITF~P@tz_U0hjIFTxtiJ1_cyqOC6N*Ek4o}esx=4l z^dF=XYDaXjzY{rO^0WP|jQF1;kSp=lMR2XO4OnUMnygkhe_iv^=={T<x*OsiD;G0v zqZw?I<j1Y2YuGQTQNp4S;|}3R3W&o0a)sZw^}Suj^=GuY4)FLw4_RU_-+edz5wHw> zrNR~zTmBYlVvO9h2b0VBRm|;24eYvC@w6Y}uTsw{vh5vB+!~u_?9ARRmh(E6Pb|im zkTxlo9sZ<_!Xag}UnUL85x!lE|3N|j8uw6eC>C~rk0(T39zkBZJTJaRjU9V@vKJ@H zH5?aU!*6ioWCzHyv01kNT4QG+tzc^e*ISjmb(DE;^Zr_(>9XHw%kw0PV74Kf#PqNL z;nUs{H;EQ$XwI8n+P4hviQaxuKEZ&#B6+Ya2(H<P!8|e8UwhGt|7UT9rJVZ4%|U+= zjDo;j+E1@jjuTMF&=eAj4tW0^l-_9SefLk&X1<{`0%}oYNJgX{N2I##WpMZDX$&pX zX2~Xayo!}Hi$A&a9={}aw19{NLT_Pb!zs$~{L^<0l_T09#w`O2_?uix8C=r2nH>_( z>)vo_<sX8*DH_(ghWZ{C`+uZjz|DxVa4c!;BnXe~b`B)mZYK7Z+i|(OqKeYgEZFtv z^2fXqK>KG!&=xBpgK*$xy?SDtO~t`bo)&6{bB}Tk_uQgAfHnzyf}ivqwXj=6);}_0 zcvFz9dp~(lBj5qbMw=23k0abIB40Y48^WOB^usI~w%o+aB(?tIsxgzJBZ679+`Xuu z%n=sUPnt6d;%NK{nuRB}f3B8f&{6l%5coy{e>|=%*Vua=trh<@!XJqD%#~rMc~Z%f zv;RqeUVpWxvAoLA)+#0oGhBPj71fSpj%m7RW|FF#0+JX7W!fv<W0TrOf45b;CYC{@ z$ga3RZxyN2xxrc@!v#L!89iiEp$=+ksyI9Fgwyy;4M-l5=@_p`wi;<Tqr?<Fmn%Tg zRn~>LG&+CvXRr;W@)rRC0smdMe8<^Uf3w>iYPnaGSF2-0u{YtkH^vwrPhV52ZA`3% zd9H1vew{w+;@|HLyhM&>UCJbX4*pQhghCA}1HZ@6u9DY9;1O2Y#vxTVO{@iuK;3T` zk!S`RLkU8&^|c&GiqDUjhsneyzfA*FxDShTpJ?^oYr^??703D%`MwohR*n<d)mpU{ zR329(MZ{y=k&_e{>zhwmw7<5>>Kr=@{UR0^5FUDuR5Jv{0|wYbV;<#|#Z;(Xx0iW2 zz4#*=l>bXjJoPJ+RbYgnNE(X<41rY(#GbXzPf&Y?_~a>u0&!ja%sg;g8qn3%UOMa3 z?E7{LOq+v`;SR!KLlMqjy4){y;8D8nNwtXPEc*hDe9*&VqLY4gQGchx!P)T5>lF=R zD44{R35NL{|L8Jk5!28WgP<Qg`YADg$BN+FH!{Pzi55qEGz)7XUdu{r9Pf2QsYTr# zx>$?4*}5h0Vh>TdM&pla5x`IC;Rr$?%EPNHrAeZBxWbLnWOGC&^@>fGmzO?Lx>_VO z=bdhtu08c04va^t&t<Ob_0vj!;cX0ngHG{-(UV@F*>XW1`FhXcd*+lPD_gcb^Cd<Z zM-BU@w)m&$N-ZkAs1zUH8Ap<cfBZqZ7tW#+N2s*qs++?%falYm4Iq4505nbxlM<a8 zz1Ve(O8<v!ocjsyzey(1HXgCyhD!Xao2HkU%BrkRn{lw((f@7MPM>ARQYvVTHKw_7 z_$fU5mQzSEO=y$Jy9U}~muH%QMs#gm1Qn=U+y3|{(o?rWC(na-KR+iwo=cF}lPR}* z<^A_lboRbxoOUVTi2t=oiL9}lGw1J7KlCeB-A~b=UM7(4+*emuhQ%%v(7?P5SWBr+ z$Xn=hnrl}LZ$=MuGxO&nbPin`g}2UAA0!E6;9#l9!=S$_A{-t0-Gm+W5=VVT)s0kz zIZcP}tLn_Zf7dfx7||fN;cQ_2WYS4qijaW13MXi$E`19F94f2*YqMvrhu|I_pyS=y zGh5`@En@;4Q!`IhP<h?q{|v?Q1l+GI-yT!OgeqQy%n8vFllJoc?E6^0`Y~_zzN%n! zXsFyT09A(PyVm0fb(@2^sBJP4822d3V7Z@T>FkVIyo%+tdy<dX=?E2(??tM0Kh(8G z=`e|=ssRMdRpVRev3rRuHu6>^NDm93Mh|jFn%G-?;4?PzweQxi=x%Ltxeg$cas9V_ z$~8Nbava$vI3F_%ktp))sH90_IEN6{Nca{gi_>I@>(bH~CL8Wu^SY$2zj`0ppDsAF zoMy`+{aX4$S-1EFnnFJ{jHY>?Oic1(_G`^1$p;RGVl?Ib^jP)DRbL_gD`5=D6b@g3 zaRGK=73G@Z`%2W=>TZtzjBN8g^<NYwqsDM?cV7frd+8FGj%>|)tR+hM^L1Q+414jf zmDJUgPMofzV6m5faMG^hc@P7(BTtXkmu7wJOm0@hO=bt4D6+`#`w;?}X=K#iS_PAA z02r>I<)2ld-qw1DjYI?WGZ(7{YnEW=Xk&gjF3Lpy+vG?Zh)*@yaF`@v?r2S>ypy>7 z{7xo-qg;W(R05Tyqg-L+ZK1vJqvA}T<F{8Rc_ONKgN{0Cme4S68EUnZbfV456d9bK zuzD&^7gOg9vHJ%W3O^65ax=S*-lP=iO~58Td&8>XXvU#3v7w_8S?-)*um)pDt=;t_ zQ(!a(YgHYYMzPeO=ZjZ$d(sjg4|z&}Ph~ZZCa*JbvR`A-^FP_mD58AFsQ8{Y+wP4x zp#{pdJ9G3@GJ>w{7>*XNT6sk_((fZ?QbNksE_!u~>Y5}C>hw1qS>K2_3m0aLflat* zZ}tIsPhBEgCVd$GRtWf%jcP5NuRy&V#|SNpQJSnjQeBe?ySiAlcRY3}%c07)%wq0V z3cA$)7V5n~WD#oGeor4p^7hzK*k<_^9TV=4ZBn)TclZld`S0@4aZrY?Olu_4Vg|9T zz&)+r53d}nd8JaN%v`BjY;uXof!N#av|-`9U1>xa{iFHS%|D{ghg^+{RC+Vfed)&H z?=P>G71KzBc-c9*mduBD8CBIa`$|)h@H^LK6O;^vyS$%TZXccdhqV^H3;%~5)ep46 z#HwekP7&emr(vW--|U}FY{#&rb2XVt-%g$n;h#rziYR@=;OKwFo>~e#i}{~?pp*BS z^A0+W8IToeZ7FRnq2Lmk;u7H!!Hn6Z0?)qfl9MpSsv>g5Dx+9O3d;D!CMtSZKYC_f ziE;g}teuwyvC=FiX0BVe6%CE-2%niMm?xDuMkaTnZARpGkhhMf2p8Ap>e`d*NsR0# z?N8dCTAqXq9f3JCn|(3Bz(CnZq;mkUwsvA}uc7C|;G+WjfLC6-6zKH}nJUgNw}B3U zZj!{FwVuB~yE0UTCRTBCGPM0ij~@U9cUhZvHJt^Q)ic%&Pw%6kgtewwhG|&G?XSk= zrmN@BDCN=Q48+6b>~rL>Z6m28>m-<?)HnYzMospu_|%{MNWB6O*6J=;<b(6%ka@d0 z0=rooD>;EGEQ_}NlbY_KyZ0KB$S~Ed`Si`BdblJ~6z02dOS_#?Ou{#ny+<`47!6rd zvpiNVe`tlb!(dsO^P-ng>kduXe6*Uo*u4!Qgb05;k|!o!YH(eI)-Ju>*CYw`g#zQk z(V%w>hLH@IrMdvcx%lhF@+jCJTF{kDpuz|Eu5RMpuM6G#&zKkd-8BsjeFq0j!wL$9 zZ5~kV(w#O?@kL=CeQzG9PY|JxNb>gH3g1!MEu7Bb%9y$wKT<<3M=lqh*6$iN3)3eP zkjTMzEt|-MGlt1UxIH6=dzpdCKjx=!uJ^G`M(PrB;sAv;VJ^S__LBr$W6s@e-@IqL z^{&mHB7RzN;x>={{VVDuPh|gBirwax=}L-7g~kS7F(dv6Yc{ikPIk9f7BwS&!)t>k zQi5On+1W(L*@yc|JC=0vb5K%^=|e6_6MCha)frAb|KyZ~t=0GTXdxO@<+}LlQSA^) z)C6ubhcW=Fou;E&P*8CDq!IuWm+LkdO8xN=Ocw((`PKpwtvk<IOahNf4cpzql?xN| z=?Vp<?IjObSlG}t`L(P0(<Vu<rSa@Nw&`^qSaS&M?ObE{XQkrlVLa8^PAtT%Qei_y zph)rfSJ)673DG#ZX<64jEI2OJ_rQ($W&X~a2%ywIHcQHmUpytf*wv@g%5mj#bP@E$ z2gWEOgZEG2Mnxp-;9rNIGg%RwRx7(3OY>cR_xl_J0Z>>#OE_L9wX}W?%&|GdTrn!r zmSl7x+xlxk>iWz)GnRk2-y>e1wF#a^)GtF^PV;w%hY`pUtt(~@0cCI$E~a$1>N6#M zDIjv|J1&E=%jWgc-8zz(T;bG4IN^Vlp~J@81D(#HfBytClq0z12f7g;zFNI&6+O6U z>4dbg+z?qQS1B^-X*=-CkFi<=7US!G#1tM_&X$b*>BEl7M4J&|?ulq2XxRMlzOwxi zU14r4HxfBGYFz<a1tKBy6@U0rv!@viNPB8>;)h3Pz5fs^5b#mgi0@9NDk}kwk3Un( znnhw#*d6mxT9wHGBX{+=TN2K6ul@#NaRR?aV?sr^>WScUK=n)a3mo`td!&RQooG5x zF6g_GxGv_}XqEr*A&aMiq-`7`sHph<!@gH3GSKQ!!Q)DH@h3O#d|VRq?5Yv~GE@Q& zG=!fYF3Kt^t-bjz(&0FY^<77bMZ?+TU?`0aeW!8d6q&u-&0yk#4zP*acE5r-<q&(7 zsbbcZFX!#E(`()A^Q5Gm%r1`n*EGPUe{OA5m@#3cD$x>+X&vLs<o>BBl0Dgi^S(!V zb&F<Wv&wcoUNNY3zLr<(NO&FC)4JW)QTu^vAo22<M_7nPr}uw)5W*CLGyD00{swck zk}s2?3W1?i#6cLH#gtx2{3X@}b2TXw%yOHYpYRarOhp8$S22X;5Ehj2P@>dfNE88I zH42r_NITC+0}eEPnA_Td024D~9~>Q2>+YDgy*%w)?aJEcpFyIh!I;4LSsZ}bAG;!f zCoR&`aASD-No5Z_At=++gifKN9-tz@nxe|}o)X4A%*?^lyrHn{5vgVE!%%M1M}@}r zqa~2hYNkf#enik;T_@a*=?IZ2M12D>S7=tF#V}d1ruWb+kNV#yB0MUB+I~E|Dc?kW z$G#XvbW0Fja8=l}(GJipv{=ewR+e53r7zb`ld+I{-RdYqi4`Lgdh)n>V&&u%Yx2-* zvOSrvaBLJw8pVL8{FZ7Gn=wWkTaAp1cXs=@Rpkt-^6)B7_?&U{Q?1958YT7j>3m4k z*^E^bzSAQg6J89Oc&%hDxH41TciSlK=6IQr(dvu$8<MNdq6whgGVG1szA?L>>c2rs znqu0dFm<!2B4kLok||foz!h0(n@H;`f{Sp;(c{-HG6PDPvlw6G*(b}Cn!ujO3-}0b z$s!wqlQ?~;)w405mdWhDdI+Yq6gv~bXm_gnKUf3?W|-V1nQXkQ-`6KXwX^r}k=i*r zBRze)we#NpHW;9|6~8|D;kw_Q7J#`}s9nhGxt4O;3`&Z}-4nxJOHNEqDURg(O)q?2 z;dsyQMP?`EtX0&O9>2WK1EOF_EAI9?vA^CRA;ta*`>xrfe3a22j_QxszClJ@<p}>3 ziFaU)9()A;Lj4JWd_SPgT&n`lfDGEda$xiqmzm9F!Uo`#frzmt=dL+1<`a>UZoRB| zOOoOr*8TNgnpg{pk_nq~t~WXL^f2?fSf86#3iGv&Km%%qV^1R{*90#^a-w_)G5vA* zCwsh;OtmsSL-RN@?vR`$>H})p6;XKk_(J>MVsX`+Du@x^2?Dpzfm8GtHoNzpD&#G= zqr&P-0Vy>MgRgT6H(EQ|%aT<Zv@E7QrjCka{T>OlrKcpwa^5Xf$h!99`qo3Cq>9S^ zu98OIP;=qtpFVx*rvTD*jD5qClJKL!9S3DxBZ4`bHExQj>ZLO^4Wkl0DG@Q?yo~pB zC(1I1jPXK+Is9S}CHv&$o7rzxmI%`J@P-sSVDdtDe9mR^<f=$B9<}v<K~%(WkLKI0 zg=KI17qaoZ!@1|2R`hE7BK~Xo1<|0_F7Xs+Tc>iOcFuO{$;moCn+m^Am)+T`s;UO+ z?W0&&SgLAjBueX*OILEHoDyltd-QYo%^k`Hr>ALUW63tggpSu&?~ivHmYggc9FBmN zNZ4#@bF;vQz)LkY!=|6j?t5}mc&d664K4xX(m_kJ$3c*04xI##alss+FWGRWKfP90 z?<gynlam`SC;8A(mkCX6AkALHN@j&0xFBbrY3j6!sucb^!D$5fsf-^dX80hH{fpYp zDUWGn)b?2nZV35>Zx;~JUf5!ABrty9;d7R+<NKGi5K1jg22$12<K%pf2y4Fx-pY}4 z-yI>&3^)fB6wv#w2P54M$cm1L+$>AhE-af5NP~HJdRM&HMiW&;2YaIkGxWER4mHBf z-LCXAXkF>9$h+o+qrrK$5k=ae1hIo9PE6E0RyzfLO4V&GNcper%?9@900&2pLsWbx z?*DLOxAz4;@SdJ?k=5|<;16RtEzQYpAMhwD&ssiHy$F_HVrV%2aL`xLFe>MJ-`kcO zYU$@kZbr(<)-AEVtWy3(ytv&09)x`UWJeHDP^{s|7tbAzjE%Y7o|-BD5LHT`jl?{$ zJkbf`kCjV!XOE#eya+@QUH>yn&te%}6etA+>hP*!U2kFp7(7b)pFZl`=El9SswR-? z`FD@{T~D<hX9`v!*~3qnT~)GK)BM_sI`U`7ttIE>LmKb*_|A6JS3U-5M{;Kc%;>qk zJ%omdKfKX9%SDtW$zZZ`J?gJeOBZlYWe?m}AQSY6Ok_}T(gUQ4Nl7hUP;PKgURy^e zBY0*$givODG2AEG8R?J5qG3ls%FC-4f}(0yrM}J?9<5?Rf3My=RAkKh8bbBq*|kB# z%+B0-CEsY??pA==>So$GOCtR9f6LxrG!kmnN|g9fHVdaN%?Bf^3Cld^uC%H8k=YYg z56wL+kHdi?&X!%K+TH9ARW{hxLRg`b{2|l?T`eMS#n0&WlC<=05#EvamX(*gKDAxM zk_mZ5L!nUC_Co#gzU^(=7n1$a4bFbOBdJ6pnDKs=M2ZCsElT*ThvNKS%2dGRQbz_9 zD*pvz+#yCo)dMeh{zLs>ig5nVi*qcM1ft!DxOBipL;Q0#1?uf@^8x29Y7TrSiT_cY zTt%$BIyTa&2#ktCJ%T>ucL>yVBs_B)yPs!q^R97nP^?rRlvc2@8Opb}=3nW_2ZVP+ zh@`OUFjsWJl-YiERLeA<s~It}cfVD`<a$<)5ElOul$Msx@i2LmYv(RF;Piv_5zIHo zfG+(2uQ*a)KS#%ysX~>D=cm23o%%WBje&R?55bK1ZsH31Xd0tG5-?ZftJ^pZ3P6Ul zJB`H5&+Y_EFJhuZDl$n?eE+7D_;wJo){Bbog@7+!?1C%q_s##9_^FRRw?OwzF8*>G zC@V*Pa+<Q_qg=~@FWw+j+l)gRW9ZvYKnGheI)tUqkp`XZ`%39bb&ad1CY6P(m2ES` z-mZSp^V@Gs+uvUkajOaHx=HpZnmzWZJ1>MfN2gT82J@o`BkjQ#5qt7e9^4_DGlYNf z^Hm-B^74@~b=1}B(h6;dMlL<udyOKZ<x~wb$YxIFv@+wmKQeWzn-QvE!%@?I0$DDD zpCmyEE0!0J7rwtI;5UY0PRZvP4VZX#aI8nAaK=oU{jwJES9D+Ten6P0M0A?biK-*j zZSY^urkRV|QoRu1&^`<lQ&z?^8lk9B3E|JbH`Vl%;Htu`Flu^wdVX%cZ%G+zs8V6v z@^Xo^G|AaHrT#61W0@kug<_9~z^X9w^dV0wcU9kQ7h=TPdubN)!1<xL*XwvV;<o$h zDh|be7ZY}FC)%&9h*Pq3(fC7(&#@Wr1M=P&Nfr3t7s$!?nlc$O{Ev2It<@TyT&r?v z;a3*v!OHiu`9)OybP;!zB8r02uZO4^cQo--)Fu8BqQFq8qO-*fsL6rsdivQ-2_b!9 z0oP32y{oE7o>f)*+W0*DO%#X}s}~LG+=1syfZmuc)*ut|gY&Qc%kS17UR)%RPra3J z3}<TSc;i&as%sy)73tS5lZP*#SBrC(`>71x&Bt`Z0tz4gblztsR+07F6o<_iyzFW2 z9H=KHBeWLVMaYZZg9Sh^kx9b<*db})KXKpUCb{s8|M>0^7H@8m1Kt?O@oG5aCHutf zX;7QU5<jE1<Iy#tIOBGD!zdCgkE??u4T3XDaWnp%M#>+zVM&$)N!e59k5`YE^^*y6 zNEfd3&EtWKZ!(Dh>vLl~G5XkbI9@*GBzC-ZPkp3cdEW>y67<1$8(Z{z1Jm8q%WJrI z@nxfwnqAJ`*xTFd`5+DU?_y&|zfr%z=ZN<zo~-u&otuDL-7qaiam2=8emkzi>)UM} zV`b;&j1AY6A;OwOJtW^J4&<l#K>9T*C@|_UDM8(gPxa-j8T_KZm7V1o7)F3Q2ZX}$ z2fKy!=RN|ne>~VG$kIq|7whLEc&_oxDK@Dv|E^04ZNl+m-ni0@7^S-ObV(xJ+5>kg zuD7RD#({s)**h*#3spMDc1m@s=&$tHK%0l*mc&9sG14zaBa0YB**Nl@Gv`O`)#r{I zu!u;Y5#5P&y5IS3n)9Sx{X<dTSQRNUY<Q@~<}ZNWK5JJt;k!1vJpi*rmFG~8;I`QD zF}8gpjyG-Rf5OJ(b-QE0#*l6@&V3+ADqO8|g;hA>IY?JhR29aXKVbKS;s3Y7Hykxh z`oC?X93mDnlbd<?(irbp>E9es9JNWWoov%sF;3QMu}<7`W=zA7HO(SlBU8RA<x-#m z0{*GE#65+4JEjqrg-sLTSn#_(5FEE`d39_pb%b-vH@jUiIkyKUyYG#;Z){4lnKX~Q zoV`PPds=yk+J*J?BbLThKeU@QZ+3>0w#2iuGnO)U5r<_J!T<9T9LN_Yo^D35yX_3U z&?F*z)NR_6J!8oL<N<7=o`h7uW1HFzB5(q|&L$<7EB9Jx%65pH-JDwq@EvryJY7Bi z@hY+e<HSRBXIZPa$7lP_rptO$9s>GRXrKndPGl=l1IM8XMgONgAfhK~v_ztIndC4U z@4)6-W6J#`@c6`&|IkKB{$`0CuB;|hr2xLqb~E?LI?F=43FM&XcR+tm+3?sz(0IFC zJkiF`jQt-ujnd{HUhUes0$y+n**N$k1+ke2GO@54UJ@c^o3V!=x#;uVnzgO%U_35! z1(5;8xgMF>0@N}4=kfr0FR@i1QH1Ii-Pgpd)S|4Krv0O40*auuRnqyD0hf@Pn(r=V zYG7W1tNR`l{MW;s-2g{h&QMTcXt!XfV!a5f|6!r-2BO8uBNOuxadglIQ!G!~4OX59 z4cha;6-cq=W8n&k-~0MSWR(;?V!N%AZ1=w`HZe9CqrIfo<$Nl-;arn;g?V{>E>DyA zn-Y*Jb=Zsc!$=)#ad1TvBa`tdSG;y%q(CNDyxo`qmUH-F5a4GZNiNLvgXx&~C($Ye zHqmR=&?#K8k{FzcVl&5D5?RQIQhW=}d$l!MNdUj<p=F?Zq8Tlia;6o23U2oXmCZ!} zjZ1&wjch+hL<_Sl39>j|vwhF4@!U7(q|2!NL6zUC5stbP)_zl3R>h#&mW|%pj5jDh z_>;&<5td%W2o&)YRCxu{l7Hy1<-LaZs&)-AHQc@5ZNL{C^(<qc&Eb)f&cTtHR*Rfm z2%9x*3h?yrw^=x7#op)+k9tWjpEIxOJ$p!^!LdG{F?)T!g}xy1_80A)2j)K79#>&b zaW!LU6g#N;raUYwmlG_Gk`ta^4{xkQWpB@JYN*ixGSBf7-G8CLv{9T*LQ?kIoMj*q zyx*ON)xUz?>9ksXJ3U~U<5$355;<GYnrAMO5XP@~+n$|ah^77Z{^N~?yBKw1B2E%Q zV3@u;j5{!en>>go{d)&)`R^ERuis9Rd7<3N@|d)=jnPvbH`<nKfw7SR2i|g%T6R}p z!<7UHAW}9becIM=Mz35=-~DP4$Ntc<fIim|Wy0Y}MBvKO%q;l%(d3zvklm>JJNHGV zO+E*|MMdw7J18F^qRq53vq0Wh-WxfG5sTP_T<0BrGpDDx+61w!YnauU{?OZ#8sUH0 zytCciZ`vNbqF+ieC1^<2crT8Zhn@!1a6zyH;7B6R@2|)2>&&X7Dlt%y_1$tQ0OCLB zFM-?`&wg{~ulbPI?UnnYb5)R*_^2HcyYXe+pU*H9ZE<n%at<MyNRY+7W?f_rRRGQN zi*UzU7tQgMUn`j=<A?qs*zfR6$OR9IM9A-*eAcf$B|11;r?9?K=<HIwV8i;W9@D!C zII%I6QrZU=<Dung>pIr!8S0z6nFm<9?>DrInAklH?Jz$?m^@<&-z>Y=EgkB)He`K~ zc8$jQw#y>AGEZz6YPW0G!HCgU&~s+9->Gj8*Vawrf9vp0?wAK9F?L`YKIL3?F{tw8 z(aekBleGpVozliRg3qBk#td|R?(?GtpxTO36CcCfj?Nv1Gfxo3JZ@tnh=L^{AYzso zVm@h|BJm@pTdY_4I8}8b33V>wKcL~{&7uA!v?HkS5nRgvh%y@rCf(!~nJ(9sH5x>E zs75<J{9`Iuc(G)|z3W!6!U#T<N&BhBFN;d=ZD))V4M({!?m#2h;_*BW(rkg}y&sbA zS7Rbe192iD97Aui9*Km867li&*o`($m&FhKZXWokB@$@UMZA+$fPYiMkCz%O?CjPz zoaOjxd1``QGZxj6O{k6fr7U&0ktk0>Up*G54?J^he7N-w=kr+<V6cyR-el!|fea8d zn+;NH!GPPdr~W7l{s8p%6biuSuq)3d7v)+nfgC3uE(?wYkBP<=8S{R`z(cOGIzePL zJ%O$ii{S&Pz575^!DX0_-w*I|t+Y<<!LdemH^G0ARVegmACwnYQicu*B2AvuWXW4e z+rjoiw<wjO9Ii94wpCshIMpP%T4{lxQlm6<D05oKWA@jbwBr|i0^B&&OTO<wp$Hy? z@)OwC^X+v8I=0cHw@2`GV%02aK8`E~dYSYPb1XJ?LmGMYgH}^4uM%igOHH@CiGS?c zQ^wjZX=Qt#AG40Kooh6Hcr01<Q0cFhR0irkofZsG*HAnGMn;`d?y5`vV???vQS>+@ z<oXFGpHkhUm@!rpFl<RbJ(WyWiy$T;4K+A%!S{WgoV;G%NHYQ}2sZ!0z|u-(Nay9_ zBg^LHvj@x3z6hdo?fj)~!|*jpg7i}FSf9Op%&RRM760G=#9-`SJV`-3s&2nBJd_?6 zm#2w@KG$38=>@s-i`yQpM+Td7OptsU8c&ImI}wZ&abX6ez>MLOiwY~5pFdW7|G3H) zZuLxDd=r?EwDzb+l32@j)sQu8fUeJ-)5R2}g_?_(G3{pM3e|4?)pN`Ed)~ljIN_yL zpx)pmvHP<2{IGX-&Smn+Yy(w(6Y<79MKb;d6Z$M<(356W?zweDE8mZKY5l-2h!t7% z{zrD9HK{lN+L4e(NTNlb$>Wx)riS4QCOG)*?`Q>`Gc-O4D60Ir3`FG6MboMH$+rrP z)Q5q~7x)lIv0?2_2oMauzB&{8i=)!i=FqDTmGa(^g-eMEDb}qIjI-WDsS#C)ur|%6 z5C7#;^x*U`JpXOJWVX$051l2%MOU#TX_T01JzzHZ_k<lgrpVUd;F9XW<+Y`CWY@tv zt_ga9SA%~wzW-_zU#2X5SK#r~WE-e8wRz9PM4#RDFaGI8-%7rhpQ|*Z^@N2Kv5e#n z9;WDW7b7p~&+0p}8S0t3`lb{Qo*f}ps_K23E?BDp*k^UTlwvj(H>ug%Zr`W~-_aTS z-2rq21cY)z^4i%As}85}{bC~>f%oZrJpvhzXNJvzvM#fC-GrjU;Zb`WeP~MSBjx%N zWcKEh+}5OTO%-92F#U2FMtCW5m~?;{Z()vy`tVFI+*_n-KQ5QO?u%r^`Z$$rm=JkW zz=ttoSfn7VSQk9A%=Qd3e{SEB^e-=~2W}S+ImG6EqApBlm>Y5qLT-}~FrgZcv`r)a z5+bCAm`u;|;g0{K<f#9w|6DTT(50l{xOj?6;K))P77Dn2-U+Xavkb~u_J-;IMb8-1 z9uvNm6U^g+jco|-S4)nkQ&v7{oyI$S6eW`f)fs&Bj<0cWzaD_KJtvlR+`jaG>?%tz zn$vfnx83aMT7e;Q!NUr}57&D?*2CwN-49~7mOYnP$;AA=-$~Xgswk^Q+3(;v?O*L7 zN>G2rPMAr;A2Z_rox)}9v!C=$z<n28r@}aYMxQ|*rwrWm#ug?gtEjAe?nv=S<elCW zY7<HXi*)(BNPUtX7-g@3R<{V)QxcGaat7|y4`Nz$bYyN7?iN8;elfHN_8D&Z^;y)B zZ34Wo_2xaD+bF<n&nf3hkWAz~nRl3#Cq7$8u6zY(Qxi<iOi$uqTjwa5vAFDlAU(A? z)3_dg!wn%8R;6dat1HIQ%Pz~3yRO$n;KcP}>GbMUX~<#0=Z$&+b6_59Nyw=p1A7*d zgL*V&{5k&tFZ?>FVXtU@gmZX^!WK|_mRqcj(btccF=q2kj;d?c;5$fR&opMNoQuQt zo#r-vLP%Usv+!eP8Xf4@jaFO$pS{WLoZ{Hpeo_htv=X#g<NGoD0mIkTH-=ETb8x?L zHT#1t36E0y2QD7bKHzAC`@XPno{wj6`<7@_Cc}>m_b&SDG*N<b#MP|e%U&27H4P<| z>gX97URvf!CV0pt!fBPN`a*bg-<5mNNAn0*M{fD7%MCz4siXAueu@cp6eQ}zH)#FD z2u{L3A{k>JY{t4Ow`F~<v&o}QW1Ky1ao6}J%^DGKaXDPQ0p$Y1ite-%n<H33Cex>b zZmHaFEZ36#%3z5Qu(@_~(<_ZcHLB3Ub;&_`F#^mLv$SshO@!C^Mcz#Lr`OpK?&7My z|7m@PFJlHRZye0zN~$q$EYDqS*pF+#;@B#7Z=kl`$@_Kes?KEOKABq<RX&cnd}dXy zq$zUyWS_5rc$A}#+^2Y<Fo!H>MntdVJVu1LM@r^OvEl6pXb2{Pth$RtG`=evDRvb> znl4Tv7IUPF9*YhEfzQQ}p84-;Y8O7IookJzz)%&b9&`23D^JBT=h{AV$Ah6=gT%*C zd>DUhyj;=DVO}4)5|7dpTwmm+Iwm;FM!So2Er|wP`LS{>y_aMhCzzwDBj|Z9t{Y3j zCGSFGFFVZ@qrU48dRz7U>PT!Iz0npGO=tab3ENL;iW~N5k=%#)VXx;s=E*oXz12=t z(94Yc{8ahF?mo{b&d@TFXWmcUyu-cuM$Ha%IdBECVz^Syf7Qa+7$3O?Y>1tFmk%Kv zYX{Kj9-wHiR~_0pj)Dx$_lTFZbxn3FkO>Qa&r(z#drkO|Dy>N>v`UpyL+h?Ix$sui z`SYZ&E~piPc^36EHUaNy^~Cyd@Oj{N+0iMTtTKyV4CeW6C=NYc?_HT`8J*TF##d_= zl1ipX1H?lb$SiQ(hl$Lv9!O2yr&VxMpbglUlVU7vFR)b1Mk>%Wn1Aelsi?^(pwlt- z<-I(qku`5R3NkQ^EtBA{&X^*H#8T^2h~dClr$x^$xa-@_A!)!_Ee*Mw4pzU5&4>4+ zLcbgf-+mioN*<G~%1MESrMN0EBDt>*^o(0nh}I8Lv|)k8bdb_tI+_^}G8J?T0H2_* z=MA5aJHL3ap19p*paNn42}1@yvxZg8(tv+VJ0_8qL2z@KIHqET-u##u`0lisc17kV zt1Gql?*-Ndi?^h<*rz`5)nQKm8BvyW=T&*sI^HM$i@4!l+5VciOEBT1&b@Lx9ywLq zvu|?exxtapnd#Fz=FLG#7~PO2P^@W4M57*?XY+2y@3YcMD;lk|qKx|Ty_+{@;k2%^ z4bLhq$mlQ=4~ms-7=ydR=`>z}dc@&o7T6GX&J^KK-B^UIDuHKTCXe(X7rC6WLI44Q zRaqQmHIb;}ve)YApUS{MaWCJS7uaew;`eIxUt?xIy(YyzB(&J{it+CRY{SqqXGxxS zeEEayYvaVVt6qrbsk`Uei+d=n&g;k6hkswum>-{8)Kgz%b*=wmX>69FS+{<5eb(1o z5|DH+?ZqGgdd;Q+yp^=o%HbR<iqOQ&arCk+r{2D-tV4piB_xG{Cg{j$ej${l(Ze{= z@)d{(qW<qM8oCk{8yVovMJp|G3Kmp(Ajz2JysDP3%<)mDj(;{ZFY_d3->}u&koX8O zjKQM|!3o7Vq*qZ-x3S{n=?!;!@M)MW1`&&6r(qL?&>@9ae~Coy%BkxP(@cGh{6erE z*9fDuLr72A-4GUK0%$SU2+0N3psm&VCL*(LfAvG;aYdhuasl#_PhH!z%buOV_ZWxe z@|y25W(EIpCHs}xq#u<_m02bcnnavD#1=3|e+xI4fB>RM=PsC5=kXv$Jc2K0aiUAi z03^KpKkijQ8hQyIVJv-@U#IfOQo=O(Eger%WQ8h|gF7nLyr;po{u_Ak&EK&%j;jT= zD%r<vxFR=ffJb@ob(kfSw&C9j`I;44D>&ZfINRb>1JyeQvWxrY4+@>veBT5AxJpsW z;y5U)mmx!hB=UqM)o?@|ImC&pmGxAgMBbf1X&877#x~#JG~BUJ_uNbL;8J!mii2d8 zqni#Iw2#I~6Y--M51(d-n0Z&{?Rv93HiW=$>a=6m0h_I(U*TB434;Kr$-mzAz(R+{ z0^&5y=`@Ukn-*Sdg+mC^#rx?(o~tcS0v-LjMQqnHIUF&Tmoi1(iXDV%Wj=6Ut6(yT z(+ibYIG>6QG3+yw<~-Aj9BD?1<rGY+krbeyri3EZYeXy^eySp7j^nf(?nrX5#Z{Ne zela@_yi26G<?msD*0~Y$r9j?fr3gH|au#_OZtxIxB9lM6PnLsp28N<?xxe%8=c{&m z@}!SjJznHyTTY0_4*;_oakQ5lnRr>C^w55{$geWK#ci2hIh8vS<BMl8kOcu>GP(Wi zB<$3q<s-iMEQ^2Sh%K^->NS_%I%+W<Bo5C87?be*G?=7cTANwo35)}Mli~t<-0uJW z!gRlo;Bt3qDbxau&O6{f{9JMFs2On<rEs^Y_!3D&AMC!n@uBeh{2Q~u+5op5TFN3O zkpnqB&EmfG;;Qohg(S(~#BJMNC&`qGFzz2gSE>(YytE7}j=X8~Hx$-pcj$B5?TSFj zcZYfNzZ!9@6_sBWj~t`tI{F|;kSm$>T?SB)$<;)s#NoG~=)RHHc8MCMG_sU1%U)dk zkovv?(Yh@`kgHuXGj*ZJ#yH!wWYPX66!xBvOcqBI8J{17ZlGHCCR?s7C(%pSxw5vQ zf%o)F{i=RpVjV{UwQd<vj$BQrmmMHTTOe6lpNU<FqlaQg`jyt6Xh~c%WD*fBZacgw z(Vb?k|FA5!u*5f}%qcJOK{TK%_|7Wxp~dAUV@p6Feq9{9r{wF=jD0jKfm80dF)jUu z7$~lA=i%7@o~y#eJ^SUq@Onjx9iRTW=xeh^8ROwE!OgvmzHed~8<MXxD<T07-oWq7 zdzsd@^`qd#mSw%Op1g=Wo9h`?X2+R`ck4<uy%*tM`%7z*NtM*`0?sL1|C&5oy%)X) z^L4~XEv!g^u*%(J^RBW9Ph32Bc2I{m(K_`CTbhVIixE~g9n_=l%*WkuHa&U{u--gT zmeSFHDm$J~pN~wQG*U+qtA7J!P@1H8^msgbjf6VM!dm5oIxKamyHqB9v+6d#UA>@d zlgFEA9+K%paJ??>9Jgy;B(=ExVIiJ$NRp?Nws=0H<Da~j%x8or=y5Ghba!kNrfr}4 z4>^~R$UUYq5JU7VP-zmc#*bbP;%c0QAwg8AN)x`W=jxau-Vl|isR`tDEB~i%G(^Vy z5+HRx7lluLs;n!jB11+${z7E=isH*xmWK5Mt1NNm7#5R)z+*a+{$nKjbd4HJ`33KF zBI|E!GL{w>2c~Z})=V3Gx$!?4$Pe|r-nMwgh%$NLI|BX$HV;_#-tqPL^7njomB<%w z3!aT(O#c`7P^~q9+ztHB|EM@H2z^J_`@HjJ;>?UBR2n;RJ}haL^Kg))TANKn7K+)~ z+(|cNuCy7`2#S2|7#MC?1&Jpb_G6~12iHq!MDf(8(#KN5!sQHd26AYkW>NI%{tRIG z;_vMLW<9@ouGl!;crux3f7^Sh=<HL7G`Sm2*b@`H-QQHxr47)oXbkM`GkH^Fq6*W* zM?aKMRyfKjb5@s`v%grICbA_Xf(~SUNQJkfYJK;d5js1U)mC5e9#M}5jRgKEqb|9w zm+N+Y*dCClV%4>MxeG1zYeVux;(bbb=h6?@b_zy#w`+aMFP4nJq*#=_g)8GMW}2Mk zik2lUogeYB0!_dgV`cXH5B<hLr2f}d2S}LKL+Y+WU(k^cTbfpv#O{|p%mfZe4-$(e zpCCvlU)LDU@6Bq<$V%TaqY#Alf*9yW=mz1qUE!9hecuXi65aIpA*66#WR#+JRN~Sg z38Z|Zv`JeT^^T_<`?eDi@}NIRXkeHKj5dX~1jAZyjsU1QAMTv)S_JRD=aI)C%9YdL zKztd!z8q5D6_Fzxua*zDv~S<synnZf^F^MKSQRzyga7?hg-h*6%oFwOZbp}Hc{M3& zoX-;b6GLLbR=Grk4dHK`dM`h#ifG@JWoB_kRxW`(PkBdnzUk>7epWIX^u{jCv+VNj zWPv?iNq7MeZL*xxNIk#hBO`6ny0{=kP`b`@!=(LXo=MZ3D#e{bU5>5x+ASiEbi2lK zVL7*L<YSw?QC)~GO?(KW2|>(7i<Faco@%_?A$Tk*2O*agQIZ;ke5%0W1z42&>*O8M zrt9SCx=Qdu89<BFiy;JJjUQoJD8(KelT=B($pCM09miz%Jb_Go^`y)nN{^4E%AHLk z@e7_$FS%Lm$*ytVzkk8;|7LRNf=+6a{f{$$!nRFXzxLvCdezXf4o<_dCie>q;QVqM zd@SJwG0`JQ)(zd-|8Y2>uppiMoToIEF0}Z1`PEDm3_Yh@8V1;MVvaoq+;K|ZkkUvH zKr%;4fWK`N`4a_qOvuBF3?ZpI`IO8@NpWY7PS17V4<uaWYt63u;%+uYgsDbxajK`E zcPu8RY<le!Zq^J9z<jzT$QE7IxLM~1@-YlpWQe1AGsE)o61H(;J#^K}ICZTkYuH5i z8?cDS5us%oS{^Vhaw$)aI_w#7kB}K47OtB?DJb2WeBoR^X{^6P@tixk_4q-i=Q8+_ z=2F4;F^1r8Y|cU?Cuc&059&*FX=h}*_Y0SBpsRJzWyeYgqRJFQ{oxj#hN%@<*zK9c zoE9SCLye|@Cn2ndp!atPRMy%Ywq=tM9*~Zr5#ReEz$kHDMGaz6PGw|5YZncG!2qWi zRCFWLCV;|z&m>!mNwo#)qH^QE(%q5UQL&gMa#E>!6Tmh2?FqxKOkB9S68O`{OtDiH z_iR{q85RVmP~s;gEM%U}_2`Hu@OD_+U2K<?^F@$E%Xw^ZLzo`t#axpLnRNOvG${)% zdcg;A>4qw&6+g=fCLdKp2ykXlS$WZ|qjP&@Qa^q85dYKf@Kyak7X+)bA+4Y%LVd=U z3hG=>-dB>O-{o6}eFWVC1P)Yf8j2!by`f182AB|tjB?8i&fpSLgSuJTe?FUvw{I(? z)D4f=>gYOn)|8QVZv8)j^PAF*k4jQn?6aqe5r(I`aOX?eU9Flifa1zXeNBD{1m<Ge z){yO1?FbqA8YmlR#3L6DM)BLkxZN?apfj?%S|%o3+|MnrH2X2BiF_#4l9gBV;pNI6 zp8TRrtc?WdgC$Lu-C@B1WxROZ59-hvr-YYB{u&(r-|{R{JU?-<@lz(HEIGv>s`~JT zwtwfG*1y>=5<5|W=d+aW%GPNeyL?2Dn4HXyWF|XYok%yUT*395BJ`WTgc3lYd=PT7 zI2e@hwOd$6)$;ALd@SsT<~-YfWc>Q4$>6(xU*k7x;K`x+6|Jcba)iiq>u%zGVkuFh zKW3A%wn!l8yNd|3zeT@c2gk?_jjWs$W-kyV)R5kn1l<D#<d?U69Bbzvig;9klOMIB zB3<Y9zkNAzXsR(UZg-q8Au^CnWIHuz9#+K88!9M%k7Z^eH3&s2T$eH-;6t#F2~=v; z1ZN9belE}caY>5>q1*i8YF^32|5J+B;%4P@I<?);qxNK#K--f<Jo_|m2ARQCy*=jN zd3nV-+EYNs%cNyRjwZxsl-twTo3#1m2<j)K^u*+cGs*{#+HsZddFL<RN~}qhi8=>W z3iEyAua?F5#rIrQ8Tlqmkvz%j6z^a5#a9*W8{=FL#hP1QuYk<`U*0?Y=nNXjH$_FU zhC$)^4Gw}w>UKIiroSt~{b{97{7EmeWsM;9Cxw9Mt=Y)J+`jNVZA@r{TJ<r;72|o8 zva8XSoXN{%(=@D({r87qs>;=!C#7vrZRza={thGAO{7z_!yuTEKOTzU%N*nD;cB$I zKf2@9SogdZtSW)mB;F$MQ|qUOArD?WZcJ1a5kl9sjdp{#R<=9Hqt%1ikI9urn-ovE zVUj=ueM*Y$Z5jEuYFtj==pP1eXBl5EV6OFb<HY56i7(o=%;RgDdQ^SE`s*z9mkKK? z8K0UFE7b@t_qKVx?tp|~N1Na(ZIs*Z;A}gqf!&nvBFZf;srJM6ay9znRjqJ5=VTF| zIhvkSM>WZ5&!bjbIyxoQsT0$VyZH2UyfYwIEcR{+fQGX_0kowGfxiTMJr95J^Q!;n zF7-0kN{z(F+1hhjD36dwJxowy>QhmlpDj(sBAmglEb%C13F@eUpWdw*u5STjrwmUe zDsfkUGFoIvaVzWd)1ZwC6Nnmoe;t?5PE%(P6>uj1Yf#9@hauqVLXaUgn?O<sn6*B; z4D;@m@|8f9d@px*6{@ZdqQ`H*P5Li`82>GNz!uOfP=C9OzZhz_Ssxr!ui{byQB`-V zr{kL_$!f4svUbF#N%cdwsAXX6@R1Kz4RKOTG!6()ip5iQiae-RyLSSC=%q(9`-3>X z;%cq(tk1jN&N>%9?gLQ>c3i+cXRd>)^tpiX<G_-ZnSVj1<xr%_EW$4bRb>eSyxnG4 z4i^ty5o1Cr$hG4GJb|&G%^2+fb~?sf+V-?b^1Q;{{rARqr)N#m@ocw*QuLLHud(}D z+YyM)%E~iS#(ix(sC<U*X{%62;KDC-$(fWvDXBDYGC#fP9|MBB11|vD(~4iFjjCiJ zRZnymgE)J|Nz!F&&If6tLc;%sVrqVy!2vmsB}>%LpW^9gY9N!Iqt-6WjNf2{ley5W zBmO$NjQ9T<_4`GX#}C+<HVkHD1Q{3e`y3jv?f9Twss3X<DN0E2P^~4brtm@5A!#^t zZ6rl{-~IbZNI$~aYy;?gcs;miNAZGVMSspU(NJMy)3~G)xtW$7@T`Jq+B9n>h|<@2 ze-%6R`Q#f7glBnqp5h%x`(YH7r?EHgvic9xmED&PdOV=f$FMK|$h#{=YQMqpMyESM zX|C#aIiGjex@j;~%%ZvaQ?qjLb_+g2dT`^a-e)VrEG=IyLjsPY(=UTYhdQrBNtrd9 z-v5Vb$3IQVAWV{H*kzY;^cx4rn}c#){Aj&caVp``A5rReX@|<DI{cFBy*pCZ)|KM( z!dky&3wS3yDxpec+cVY2$S`VpKmVl!(FZq|e!mfmbkA^d=~&@IDBt+~{O+3KL3nPp zxu@Q`^9%lx0syfS0B0Ah_=HwV*zI7&^_X&*tI>jP8>(0q1bGY#lqs79H{boAnSg<6 zTf==jbl?*$ZJPH>`8|2=htXz?^|xCnKpn8zpTQ2Ip+?Wd4Q^4o6}v{3*E0}%WfvxF ztGBmry~tv$p{O!b^EFmOy6tzK>X>MlXUi`kfHW|vW)K{YF=nPQiq8}s&D5h|mNw3A zNEKd%P8#MrASq}@?0tb^bt(x82ni;b(ITXqmU7k5q$qU1!%wKT7$Iv<WMQFgR%?)h zr<RN+l|~uaU0sFQw?xigg?Xw{f;c-P+fIzwj3)!jI=n+F#(($V1zc{;@4h?iyaOx% zctHoyZM9-qpm%0QX~5YAYhWWSR4HQM`YDrXV@a<!$6zpPi~toDfR^#K5h&JHN9jvv zrb|`(yAzt|Z(QP*{y&<&f-S1=3m1QYNJzId149W&Np}q~w1AW}NOyCjLwe{2NkNd3 z2I=nZ?(T*={_nkC;5=vTz2e=gUhhXG65ri&=I+Ag9?A3iQISqHYl#4bwkkGeisZ(W z4x!Y~7p}@3A#ys}{5>m=I>9h-VM^-HSkf&C!Io;k=QHM6D44Yyi7g!cWVY-yDj{YL z4<DZz{p7Z<EtZVo4?OK8RD=(Qa|mwv{TyzugFW!$v!-+#PiS%F7SQW0c{B+-YZ;Mn z5Vg9^qrN1LR8+es3@30R=ePT#KBOu@NCX^3sy4nla~l`ot`{gk=9E)N*0>dVVqrbY z8koRAd{iHTRQ^HP*{>DM*2{O*D-SAV-rJDGmgm=>6bdqDS@I@KV<P=Ia${1<op9x& zRX$aozLh1rm!%j-y;79x)>^#wk2C6W+?pcDd>LXEJpGdPviIVD<E>MU<GR{3B8jy4 zU+aBDi)BLm)KoxrD($6$`^6BQzPk#qulFDjiwR3J)+-9BT#-DFfnIA2C{%87+;p8n zMI4|eqV9#_@ajuGyy#0GPY@Uvj6LZ;F6xIo1sd>k8Biq_RNk{q$YDn?<iXB4DT$X? zyG}5h$gi5c=b8vnB2+4kj>{!3w}Lm#r1vf7U$8d&&O8M9p+U4i%rCag;z#|WSphD; z!3gsnym!kpWgV7xYU2GHkAqI03?s%$UkXP?>l=b?r6pk%ni?$YQ_%{1X9N9gC@ysB z-`?5;wp;0IqwaO~rx_-EZ1`H9hs0SL6?8p?shMT4z5m_H`_fC*_plJ(P3Ta#aj1xn z#QY!?{dmN#VD&DE;AX{HPEOM25ee{}?DErU@bqhanP7atQs59+IMp!L+tS*ItSs}i z&XhY8WD=g5Wr`pu|B280@#ptCYXwQ3TyR3Fs-eKY;_m{|R85^qav|9{V~si8sZi_~ z_2P!y3Q?E>;W+B1q`(K|$Ck)GZ9;<=+@oT(K?*_tvgm}7itl-n8z}6W`hXLOP}hyq z583cMdu#HC<p(ddu#X_RcZ;mAaS~vKt6siuyn1}9Tkg?*73x#jFkjY*NAIb=#_A98 zrAdRuNBo_&)+Ue;5&j|bfL0;5P?`uS3NreHJKb8*-Bp;x=bAl)^-Q;h2M|Q9z#bH& zsVUN^-!tqgw9gpS*S8A|Fasf$T;|fdmUYf&HqSj-gu;)vrOf78_k-jm5H*Luu9%_7 zp=QSJI0C0Cy0dcLFJFoRXyzOVmWzL<{mU`gNKz8yKWyuO7}kRIScbQEj>m~6;}@-P z?{A72f=u(dEF!feDm_uhxC<~d4(Z<MflR%PQkj#68<a&y9_FOt0He42(}dS)Xq$OE zud`p{C8)?MoN=3D<p|%Z+#V|#b(?7e$L~KYwaPv`IuSQU*>a639;p*3sfPE%f%jt_ zpQJzLUUz0__EH^xMnWL`5p&+{#O&PC(r<(JzUApb)%VhlVfjI&t0f=+wbyJiPApGK z5aO}N-Sre=D+s{>ipP@cGE`_z<k5-l_OkXyEujC(k$L@iI0^YA0$m_V^B!Uc<at3p z)cr6<X`;sPs`?AZgDs~eEsbJj!$$VSAoy62i)cHLl1&rzu4VILbnLCo;S?;JZQ&7B z(Q@&<>{_K)Q#eic`|pk|_#YG~>(jQ%pIMX4DYsW^+=_rBfo<E;Kw|`HFYYDfwA7tb zq^25t{lS}rc1Mfa`EtVfUoP65T|V!Jox`tBoO@fQ+il1Py^gQS^==~?MC2cLh=nJ_ z78+g{e%cSNM@q|_KKH1c0O`A31|XsPT1Zx1_dZ^s3K6X{X^yjkcea?#PpJC$upgle z{tTZOSk?jQ!j4&ZYbYcUk6%-@v?h7hXdC&e2mjI3{bnnf^5vTYrC1%L(&N8MjdB0r zt&Y<HgRt8wth9Ihe^=MXajr+A93fDxI?t4qr;$|3`%UMZ&!z61rJI3y$`^UbpU7C0 zd1z^$2h>h;5QY&6<yMkp%U1^kZn9O?n5>E5Sz5sGVa(-+`a8kV#+Ehu;yyd>GCl9A z(AA$k>k!nG9rz9&p_X-)`6bX81G3r$SiAKSe`n-yW7>`KHQrkg<HZdS-^B(5Z?Q~P zy~_FP?;ML$Cma`7&>M#2aVg9pVZC=jCax|`{ULuOlcRzWmjGuJcvJP)&F`M|=1vQv z)D>VaFCP;|XF)9ai`HA|<-?u7=!^Fk-yXkisa$Ourmy2D4Xuf!fGM8*_~N2}n_q76 zyx8&441W`pV)Alm;i8mC#CFd4QrF!`=}cJ!cSpj^JsuEo*>3YaEtyZ1BSxWoJl>yT zYRzr*g&3Jx2$-xz{+F8`^D!rD(r@YoOc(z9pkg?w4j5}bcOPqiKi>~`=SDW@e`ke# zv~AIK84F_(dC1b@J!N-FGRSv0wN;XBkPQdFV+yaoIwfOkalo7lH~MdmFKHf~Nx>k_ z$YFCc_JN$Q;@f`1ITj5QZEUiyjn6$Za>+n)J=>*u;>KSeUnX+P(9M+{tt8AmAicFT zS){s|0yY#!IQCl*<z<00we__3I1V32>X!%lJI_$L-P36}c0P6rr+i+6h-_n~+;OX^ zlp2hvhF&OSvP8~$c2&qKGkDWWb-15-%Lq=O5tI>Wq&ftVhlt*N7!V0g_}O7b)QRo$ z21(L;vWJjjPq+VfXug&Av^7OA5UKX}vcfBr^@(V>^^D1uEHlQIY}~^pCnk;E;n8p# z%r%qrRnXl)<IoPn(aT@Zk<D2%v?hMW>Ep(#jnBfaQ^fPa<yJY>LlU}MX-3K+lK1g@ z4Je9Pr$_4^|259rneA1BV@I^}{eHosu(5mAjE$40r{tR!H-mzBEj5NgU>jV)ir4cN zgW+z5>wzhFM3*e9;CqqtlkR|x>b$;Weu4Td^dBf37VSrWg6r?Yw&@WyCD$l7L81@D z>u(7|%VhJFlfyG!pKOHT*JC8tJ2H9A6~m*$3z9ZQyf7Mw-;WzXIf;@CFr%gaqHU}U z)Q?n|`VS=uiLBiHB_$9xTW9n0%9*w7a1%)|ZTA37L3?Z!d`OE%h}p*G?cpXHUZV)l z*HiqeD!oW3XSt}^32HpawBLv9PvMEwzAn$aC1nWu&$=E<is$j(InB5cHAHrfOa~_p zO(5)FvzFOqs}W?Rpq>0@-Jx9^$%iw;^g)2e*H~Kgo&ik504SO0rkP$3-~62$xwuX% zmzci}G&GLGjig+kM!c#VuUG<g<=KnJ$Q)C1b`nlSh<%l{T*!XD{PULf1HIJOtP8i( zj4XXSE&dF0WqIkv+O+CW|B{eZB3E6A3TW?Fgz5#-m#z7Q$D>xfi`Zzg(}XV)AO7eg zcfG#ql#^EAPy?(#efT3QhqkTdH%KP`5w(~Y60{`oua%ed9EEKU$UxuxAurWuyPJ}0 zgnkg@huB4BB&s0&37@bc_`Xw^h7P1@uzo&}#f%*s3F&|K5*}O(Ja*bxc^zkj;fOMO z{CoH>wxVAI#yn4G5r$Apb|Raxc@}6RQb6!MR0nFH3@kte%d8BLiOko4B{4cv50A|5 z+e=v=A~u7y6`%f?)a1DU7lRWJ7*vd7a3JZeg;JOaCsP@gJMN#qdHMSKD({v6zAcR^ zV5ow?rTF*Kzo3{A5KnY(@K=zLQTJ^}=ua^z)O!AACb_!yd4I?CDB5Wpf(jmV<e}v| zhP^p}&GC2~HzTMv7>2)^=(RFpqUaJEt<u-|8h-A*8E6lujCP?*yS$eo*V#5tq5Va9 zJ+;Lp2EmL~R!Bjwz1J$|$=55we7a!q!1d)dES@Xn%h#7!94~NbS;kJ*OZt`s<$PB3 zFIf1;KEjDG@-fcL_&`#yRDd<lb-}7d(<Pwv{<vHDKh+O#B=f&6;#U}Ts;1F;UCc%v zULtIA+ERUC5Umk)e5(tabqOKfINX_c3PVd#Ew>@*0#E5)gJj~W&Q7TdwtV8Hv+3fM zIMnQ~p<fRr3L7vgFzA`m=sr9ZsDwq{tslqYi8LoKi`JO@)y3BpM0gqCiNlW#1?oKB z{m}Q-Od3A_2ykrsJrr7Utt;>`4p+6kdWw&>z>qqDgnc6@h)Jp%)9lIei2e%CL_q&_ z61bv1_fOZ}=UIzOoz00D>5<yDT2q{DzotBP(6k89>bM+htQfGXaJ*7X)CY3y^Or;O z-fYwgc8*z2twdLjIksXer?xKvINNLDT7@CX?B7hRf7?i`SIj;Cmw~DJvRH-}@0OZ4 zJs+ti|2hu;?aobyh!4{|VVvX9{0C)Y+N%VU6t>4UCIcVLW3Ml9le|-)E4Wd<txWM; z?+ax#IW{pkU_A+QE+j^OR|4jkg_~p&nt<QWNuMC{K&GKeWVae->l1x|RTsl2wzjm| zhgSh^j0{0pDpYd$r+cZ)Qcm0K1BEZ&uC_A{vod6QhL-24x=LwP6o!|e2mK_UGybNk zYrd4-Xt}d}Ym{G{_$%n0H88z*yx`==re6E5`d8@tE4G!0$@R2eKcMM=ATEwHy{RB2 z%TVn~-g>6VuJveEv#kbr?S1qvwFlF#ndSNZo<;2;I&ya5cik;Na4!?oBjOlSM|jtU za8Y^P#i*!f0cLYD0I?bhk|%tR&@(-{z#dt3aD&%d-~aQFn7L`$bqUWK7coicSKd;f z$+yfALlRJZb-!7YBki>Q*O;JpTUt5FyPk*(+F<QwQRc{$6hK4_%5jf_@rs<&XO(Io zX@ws05u#cul|ky%AI2J*I9>=~^$|-N-Pc6QdU{5!{V5*E@{@QeRw^V94xZQO>Ijhm z<1{LM4ir_Td7d?Fw2X@b;c?MJ*?-zM!;^8q0ay)VBc1odTK6pE3E^AuIa4?#)o*sH zYzW=E0B{i_u%*6Xdj$$~yNAW(?DuU82cr>4OB1XY{|?v%_HY?=x5A@sx1dsNa>=@5 zJhjo*@J68UYExTL%Hs-;Ui0l+pV^Y~3db!j^m5<fX0s1XYAvY&+>((b$8{GJ`?2D0 zFEisi`1jRemrI2VGfr#@bG`w8-tO7S%uchZPgWfPsIJV-bzb+u)~ve54G+=3N3McH zB-?a26M<XFregc(8kes_coCVZO}!_+W<eu9`tFxP53=Kq7Cm`)e}OKX@L!C~bX|-L zv|Z&c<({gU-UqAL&@Q<D#Abp&K{0={hL3Ze+lde$%Lq9VNL6+)luH)*)8Mr8#}zZ_ zTaE!w5<(kQJzAbuH`<ozCM%P~XS2`kRz&!*{&BcUgB*tCmA{*!@E;PFzZ+EhH@HPy z<~;QGqmH^|bMK`_F9Lu67@{dS=$Mn=3b0r3WN!=`DhAq(g@1N>NQk!4`24M_;B-op zW*Km<i=)XMs}T^3jJ}0{berG`_RPlAvH=L}gwh;UxvG2E#<PtkmVkXE1ca-=F)+s^ z*nyf7T({sY5pX$-5&i#L+t;+X&LPp|4aq%0+6oQkZKvMM$)agvJduZL#rHQcQcwO^ z=U34M*FU->&W-qWfR&j@<y7|{?5Oqmhg1g=9|%{nv@U({@~~D;q~BnIXChmGJjp9d z^rzRi2(NJye9PyKL_AQ<UZ&noXxLyleNWZFvPKN68}<o4dMDdoRW9jmPX$q7VOj2; z?Hmlv^8f94gduWo9Ij)VW@g)>O-1is9(HRV4W@ftidv(rOX|R|ndkw%kAdZSjsxU! zO6X6+e`r_;T(SSvN-!nls>T61r9a;qFO$Rt=3p5*glL+h*wDWF`tvgyWWBVepVqyb zZQIC8-8)e~21zsI4Yu0Rv$~d2snBmsE{y7W9Cx4Xc6O@=I`>d-lJR}Mrf)9Y#HLvC zU@WkE>#VSkWZR@2o%|`Do?!it`lE&FX-!NY?E+C5$){!Cl5#MbepUtWxFj;myIAFZ zM2vztbiFc*GE=6zx$`X5-!*{amYGha7zE14U++`+owCw7LwKnz*d5{|PB3?DVai4_ z_jwx{geDLP#~F1My=9(pu;d8Xrd#={fQm1rjP`kdW!F4Ijz3E%n3ji@5lsXlJhb#6 zJXl{??|kM$sPrP{YYPO(hHFJN9T=0Pd@_wQQoZys24OAjbZAJ8ivlzsEObP2IpX7g zJG4gr(f+=LWk<$$HlZUYdvqNennC|QcWuyjK<SE_aX>yKB_)IMu5eUeXT7*wcU{w$ zpk<4;DsLGhjlir53hA4|mCHX;Y_r0xbd@vEb{vnxBe*d>cm`4fDc7l>syK;oIsWCo zlGuL|<u?MF-O%4f`0XF5Hz)A+`#9WANrZgFh2;FEBgh52`<b&$>s^^AhC=5zsm~Ez zGIXd9xr6}lUc2QdfwE`0%QD6|x7L9mmwUaxU6fX%e=`5PWv>P_i!4U}T+vxPV~xt9 zG_4LBle?D#8WE9IHq@EqSXhj8^Vpdl72UOqUqflM^izz#zP$g@>R@@+{jU513`kzY zp76^4z-d%puTGX`5pGUiq_WaYjQW7AR;nVjnP(Aq1g{YBk)O5l_02G=&)WR68&*Sg zw*J?_+HBIB!P+O>)XrEBSNCe3<8hpEFc`j`6*ds9IO@AIz|u#3P09PMOzHLly>LDx zkD=>w5jBpv&@v-6`(iafFL?HCZ*R8E0>oMx^x^9nGy4PO>$$hCC^!oGDvJ&l=3za5 zV1&q;sfp(LrDwBkBn4Px=9gF#_BLx=BBusc#|?IrA=^Fatso8I>Iu`}tFLmT-HWIs zg4#fGq4NDQ3<e*@eshGOs>E~x33~TWp=PBbigHEE4HH>Atf?50J6H@e$;CaQV3bwK zeYAeJw;qBO(atV@&RaHce(vj$mEiFfqdA1Q+}}lNANImFN=qU!Dv%vN;4+d-0(g?9 zqkq~zOpe>Nw}3sxSsR64c}kt_J|5#m0|#{P|10fzsGm>SsJQ$5(khW9GT2|k`IwM} zJ<YEO6=Ii44de&w<$>Il#ut&SBF~>;|EZwvqn7#58nfW{$*o1?ooA}o@hN*KGcDpX z=whN@_y*6lH`t+Xon+W_9n9Cs$W&~3GOQ0QZ#;pQE>Z+mBB6v92KO9xz*AKjU?(b~ z6b{i!_0Bk>yo1_44BvbJXFMKrSK8$%z1WWQN-yvT9%tL=sio44ovgS!t{1v-IrHmW zB<e=9ZFvg4H{PSBc>ZfsO_{!$1^D>noji@VYx`~kQ1@r#p^oSwd|8NH!mRT4G7^Uo zNDV6f)q!HTuk~jN<j(-{f}$4CF~Y1>$RjSL#dJvcFJiD7H%bV#sLDYC8JX$luGC8$ zlVuV*1Pvc<7acx9Mfw^hW2c#5PGGbhVnPCjf%6tO;)kjgWSk<|ij%U9({qwfJnPSC zzqC0lbj~i`IZqHz14p<D&lnN+qpcmglJ-jS6?XUA>hkwT0?R2oYXH___^08_rIeD3 z$(d>Q6$CodvvaBEk(JMz2G5o2#w(mBs==Hi5MiSVMq<-n7lui1E9X|fu~w^r=<%7m zaRnKU<rmqiCo;y=Vq?)h;=-qYe-F$iXJ5wub&C`l_=)w3@j*c}HhKh>^cTfEh7Qc# z9~4$O8Y8kjyS7mZ$G?1^uL6F%CWJ}AA3DDUFEEEFpXw&4JAwq^C8Q|4R_|0(#=ww< z3bmk_Kcd!?HEivNCzpJ)Z~cR}bJsU>^l5%CbQ;gL_#5Rq#mflqcF$D!;${mO>=f@z zd%Sp`{FT;(&#|BzG<2@q3!EOUe8k#aG>`MY%0JYbhU%Yy6agnABYzYr`~qexFa!M` z;`xeraiOI*IT><7#r9SI+WKq}cz)ytcKL_nPB&g-w#4OrRRyuq{g<a<Tb3_tvRL7Q z&&lJ4&dlZ$TyrmYcCXQm2*K&-&ynYPne6dmPI_=k=XH5klhoSAfujoIS(<HYx7vDs zheuFzf58592z2i_Ab!y#I7y+5lw4#O|1Y(8+NS9tZ3lsU&3zM;&uy@=#~N4Z?%`*i zDKcR2<j}RTBBb<-!aT2&xG*NqvaCSs-6O+jhN?A-tmZT{R5aXO6?YQ1w@;4p3W@0| zuYD-!Uvv;7{*wG2H&(m|Y<2u@pOJ~(&*GN-yGQ{8(5D)`bmr~y*+82|P%HRP(Q>xO zF5xGGdkp5QACm&#BgpF#wtRLho>NX-`@?cYED^eumWD64OcQn9E1VU(V5^Wwir!zH zgbZOPaJ_oKGBk47*jPfSW_hgm5L9LpDS60c8J0J^cuT(cpvaj|9Tb>egj8914CzPN zHs(K&2fUBAYVWE<2+#aZcsp+;e<@Q>$Kt(H4YPr_&)h;w%L%RChF<N5z0V_YgE!!o zX81~L?`kOB$HKyY|34r5wmn-}snr)v%I_OKrw4w%=}fZ%^wf~t??1*fQ2wq2qbVX^ z+<0<^`BnakalLE&twl&!>p6H}hdddE4@?W~_h3~-qfWCL<f-w$IJQ#6|FKD!#XzII zqb+ZF_2BC}`Qgy@t#rp2_t0U>uh`I|Px9dd+yZ^%HyNAL8yj>SMzhI9rNc9~%`ZEo zArrN?Ym{Sx_qSpN*WADTVnAQMQ&XIXR8V)~P5*MtgV$8=2}~sLjUHlf_Aq~JKL8lq z-TE^IRpLRva{AYc?E|P@0IwYikfzJZ-AMhC&=RMRoh27y+$bJM*_}=hPaq6kWSymx z-U{Y8&BK%gD=ooQ-CT>QOZSf_-&hi%>SXmQv4*)QSg+?cb$4q2P5z>#fcqVro$yUS zX7-rzW%7-}O|$t+-HykD>rDjqG$5PKHg)VY!gn*~wke$T{Or4<dor{Xv+AwWaMI5) zW@@RKs5tO!O;OcQ>N(?LMj!oI;}aWjGQ0~3cyNjNuyrh)Xy8n6cKk4>^UMBmt>-DL z_jng%X~Aqqy1H1a-^F3{dARf}?j46snM{@dXJ~pulW)p%)rdHb;JYu3O#o68JFC*2 zT*aKvz?B$lgE#Gfmw+HuvA`BF<tL-ngu-qQqeqS9i&t%3c6!hg(Udx9LxfMH^OV+B zdY$}y4`kk~kU*j|&Jd;*XL13}W1k7fAI{PrXR6+KYGsd>{x1h9<3D5+x?Oy^O~QpB z&vWyuThu?EPq1y&8sFw6ZeXJbLDJvI{Nq*|wHZZINZ8s11DUY&PViM^eenHv!HwUc z!=cYkBRR%B0}A2(it5(<#BdoF)27ymQ=YZA5j!VWBu>8bq3~XXn<KTd$CHZLsn?n1 zJcvq;JkIH!Cr;t#78P5?xhUg)>G>hUcY0oO_=KT*%{;JYp#KT-8`v|lW<+PcEi$Bd zE+m=T%;-$Mf{shgUSd!TmXhx^fZr3EOnjC#vQ{1~Rz--<Rx9la@f1~Jo7RXW+E=lN zLkI08Rj3<Mxah8d2UBgx&sDaJ%!#(z3=1fqU&CnMeL3Wva{9OllnN^2SnA8YD0B|q zs%$I1*+vrG3cNR;2e!>(#|pEZcwRWujfVb9a()xO)fLdw7nm4VTIp#*yQ9yAP#qj= z{d9doxjp**$Ki8U+(5ZD^rg}<^^FdkZ&yPL9Om*2K?9HXNyK)GwQXk9VIf@3@WmE; z`NQ1)d;O_8HON)`7&5B*@Av7lw`0bwKSduz>>gdZ<(~Ef&$5~DwbL8*C4&WtA;I|O znm8(@&Z^oDJQG+x8GCISlhKM3RfYi~Q?m)^Z}zpiV)b8-=m*W#!x#yFv-qkpXd}&T zR)_Tw#SA>>Sk9=u*Zu~d6N~kOAyRyIRm{sS;pq(0{AK(l`v+Y_-I!2@*E#Hj(&Vr{ z;IJOO%<~2tSbDM?4ugi*@PV0d{;;b5R|>;;*Eo#Ib0R4gUN++aHq-X{2=2N=tWB+f zJ$&RH6VX>5g(&||6xW<gmb}dn&j^8B3BhiawiT4OjN{Pvu6Py+i$RNn&#_edMWY_m zd<sJ6(Sxp6A4G5_s?3CPsZ!|&<^z6Oy+`-t`32-#%?KCl$ITwZqfiV-YO@q^S>nO4 zXdf~MEp_>splCdATODj6RX*R<iSe!G9Ix1sk*j}w>9qNtzgd6M+MffCI^EY?-M7*l z)qbC1qIHy<EII4BpS-JH#7n=#6BQO5&vgP4$e$hJK9k`4iX%~FvnI*bJ3TCf8i?!6 zL;xVrS%fiQsiu=~cl-6CU{=X=3{uR!R*k2DFF>pE{M{Xi$f8oL;4)ONAo7ghgxABD zslIpgj(VTf!xnWESDk66%xtc*3dhThLouhq3h|HyTYX+ELLvK_Zg&~x<RC9|#aCy- z9@O=5{QcO2#f-@X!2z$AOVZv7hP19G@)w{%f2Sw<c>DBeg3J@4?9)LyF;&=7I-Y>B zOaLTzwG#>^<SG5JCb^TrumjS&0ogdMnSAg7Q&;0v;}iV*_oATh|A|gZjoFZjpGTQJ zd>5QSCPP8KWU9)%`0x2MBNL_68*CN7<C>ih7mI2jFE{(VhV<h)SqJyOQD4y!5`ZGo zu`0{=J}~ZWa8HW7vpaK-uK`0*H6NIBqjz{Ahjw`Hw=);pYLldLaf^d(*m5oH-gfEM zLH%kRbvRsONFq!Y5HOp02EM;Ezye;F4Yxho2wqHyscGQUr+8n~ZY25dz#J;W5bHub zaK))J;@bc3CBWQaK<L{BGImF!990#T!ww3H4y*|0QHSBCqVZ3^^16aO)%!$45OMdh z8NbOcU~xdhpDU+r!!loiB6VmgAT=$pxa*V8&6)F70>v*29TD$!6g>`!6I^y??MMC- z%dd9));3kb*nF;5ASFg8Q0cC0$+w#Kgg!A6cL^-~c|Vo(Z6A>It4bVz9VhPI$R_S) z8gxmu)}{KHlG_-94pI@C9y=Xen}2`zsg=-BpFN*$!{^xdu+POc!V^&I3BpTxQ+~Le z9;3xOHZpg%CiyDF5hefr;Sbu;CgUkwivL+j!FEn2^45>!uL1!*!dX4y;kElL$x`N5 z71nhq=#1?^5I&_Azsx5Umc(SQT}om~tuR4BsLPS3q)H=o@~asJ6b4BZWg&okz;l>> zz7<BoNtZI69fwXg^zeP}gvJYqubLQ#B}ekw1?h6RR|gPMqp9ym&pLN~o-RE&dwuok zd)Xe3?1iH5dGD+17x#Ff+K&6IcVDKqZ8>eUekwx&#B^S)=L>P(3X4H*NP3<o3KW-d z!qnG-V*YFm6zJ*?WkVK4{p|l07QN21y_LWF=`A6@B_TS?-b@{Ph$ZizDvEF{!QtY! zhcWzA%|6airDpeS<(x!dvNX1__YDlJClx(Ib%>eie$@L>yK_y6ZR=F)qrzq;CTUJ6 z*ket=dvqp;hzJpssQ?d@&yGKbIuiZxX_TZxQE2$B0!kN}G9%OO8KqQoh#kz2c6Gcr zcLf)+X1m&e%=M|(5cy?3$rI(S_AtDDhZ*kJulv7~3{*9T!w|t7uIYFgUh4{A9(yCR zL--9*{yi<J_KsE~!mo~}W35~DKONz+2rC8@h2?CEWNyD1we$SfnC_EzE>ELDh+S-c zA&Gp!sv!_0K2Jdqv!5Z3llw+{bW8km6b%Dmtco8}-x}b9F()MYbpJ9u_w<C(^l&sZ zV>3N+Nquqboj$j7?eJxUnGAvkg1Qel#SHpnLo)n-?Wx3Nu6&bA6X{S@A@}{kyj}_< zoV&blpf{B?_lZe(7eb=1(ien7Bz~TaeATk?Aj8LXMv5W~{?gQmZ1)a?i_?k5WAqA5 zGS1Tz0g>jXq5wUFWuhhQ{Q+a=bq-LOvxo*&I1Y1A=E|8}AYFuI=a;Q!BfVG2&=L;E zVr*bEH^aKEXTC>Ye7jX-Y`N2QWF85S`(cl#D>ESM^P3Ch@(dh`taPZKI2J??k8#!o z7o|!t9+45e>RQvkAJOTkEDBj)(@Y^ijw|I{f6F>Vp3puSE&IA<X7;x_ftUx4(Uvl1 z_UJr!?6(*x{vFNVXYDoCv%e$0*3@Mae5txZ;B**NdN!p*c{YyFdqEu5pXq4;40Z!R zm1;ptmK}Q&xZ~b<8=1U!bQLG*F@4-^rCxD~LcEp)(`_CzF9nF{NEv2Ke@<}motZWx zW|vog@o=%kcxe8O#Z>s&IvVDOE9Q@_a-YxY!l!Z;0CJIu1DR53M5>#LrrO>4I|)g_ zl4z!WGcqXaHAkI~z6pV&ojE;Vr0NHph+UgfsMXVjHsYJ2buUN6#ht(~`D&@6opF~% zMg`#IFHzZ9T8|R>^z@J$e!fR<n44dM$ZePzS*1LaN5$+s6+CM{#ql#pe1L?HqfoKd z>gci7K{~pnd#xNT>M3M(-R)QQq6SqN;y!AJ>Z>pv*CkxN=_fqBBnDnUg~((vZkAOi z%VbS*3F%`G5{G@RsPI3-lYzrF3)B+DBCtTeK$XLx0>v6vW699GvG#NYAKkde4b1GF zlVRyZt~nCK$0Rojcj?_oVao}@*B3|14WAALiqyQ%$AzOSDK8azGIVzAv6fMCE*GDJ zhqV<)W(_+JS)6Fj8-bl8ove`djNak1M<+Iwp`JKJ4eb1FTS!9`L{er^sa&^DO0#tP z(5Yc4el4gBAuU5#P*}tG0k6CgSfF-YVl5_QPJj8cg^w2ND9=7HQ5Y4b%%%a2FInfK zw{$FhMOb`qbt=mtn%geKnl6jigCm^Bi`g%p4*PT^CRV6Q4Zvj#D<RJ_Y1ENz3v{&> z4tLO$L{dr3@(;ysuy$0T$qU6+F}YAmZ^F0ixAYBXz>iURHRxq>p`rftI0-Tq@s78c zlHNaQh+TUYPHet73U!2y<mQtTd}QnLiT;MPF5wdObbuG3@<o;HJ~8F9Uh*=e`K47% zCT*c*GXC!Z5H9uUSLC}zTt?)sJh^(|zw^wm_t*%DHX}?Vc<1&yP){dL$hS@ht;lXy za9|>_)-7gy8AAD!<PfByt|?uVAjz!^P*h27j)aQpe*CPY7EC_(0IsvnP{P+>mR>$o zd)#Vu0<!q*3DIBFQYH@#s5#K*FaaHzMsl7=Dc)m1<_FA338a{&c@&t9fwwyODkzF$ z>D@;dnTWzsEMQWw*jEu2Se8PXAG@WPVnrQ=_FryhXqlpww(BwJ{SGMM?1QMXlPfb+ zNKEil5{CEQ5Op`1!Twq{S6l!mzb<6>j{4ItovynyX<jRr1V=MzD5rVe6h9cDyqRkV zedG`@dNJ;q^FhI2Epa^7Nm5}Th+*oHWU7@E;p{OOkxZ@>Fh;S=z)P{<jU_ZYkNcuQ zf&$H}e)(hg%6@$F&ud=P&;4kaa-){HJTdFO)aEdA4UA>4vZ#Z+H%FP0me6pjj0B0i zMci0^5RGb;FU?lG<Qt)m9$sc-frlPmhFBNilX|_dNKb{0k}3?RuY5&z<fjwK@}pDy zh(HNnkwuM@x-;dgPUQuGo?9mo6J6;+vKJOk^A`hf()MMHC_C3&Uk#D7N}Nz>eQ8pQ zDymjG=lC!;pZAxj=8<Se=N`}xH}vp$trvMj=Xi8_6JxR%1#NJBYJ()zL6k(?ZaO|7 z(t}hZUb>UsJE(5tQt{TF=G_{IjjnhuO8`M`RP_@ah)l@7oenfOF$>u)B~8O(bZy3i z$880%X+sLOO<Jzx&}v=#0_rq&rPn5CQhELaO9p6dkGCJ9o_8UgqjFzQ9;u!NMvQLb zm>DuAW}aQ^vU69`{LrY(L1$+M`8<F}VDXZg!iO#-yurSDIuw@w#6otnnM%})RrNmQ zH~kq5;lbbgWPj)R1%%GE!Rc}>=n+b5EW_)q6njQwJp8m}s-EPMCqN2D;`Etq!jG?W zv0X1gVTsa-1M%E+qHi(q=2(iC_It!#2M}wuWmVv<f_9z%uT(?2__etJNnW0<oQ^Ec zTsnRaH%?hv?zzSwKVy3xBWrc2_}FHNtPji5%BzIprE>P?M^1bm1Gz`$kL<G|e@8X! zey~@63v)$BN|>{Gf!t||?2q84hSVQ94K{IfSaS@NCYuJ6m~FABKHW&m6}>R!ii0!M zO@idqbDWI9TZ*P4n$qz3t7i5d0wN84qKG=5g8dHyfPGBGhA~-7?cWL;)DpHMV+)BS zWE>(<L1GomP?(PRdYP5DL`&E!T=FtVdSzZ4pV&?TFCTcdj-I~zpKya}$!28Eq<wx^ zg}Z&7o*0ouZle4nbFqAl*-K|gDWQ|^A?lyRkz`ZEWyuO{?g4QV{$E;h*s9|3nM%6> z(m1^!WLy$zlmAqQ44|sS`}$Rh`>8Gp$KGLQY|HIqLn0$<VGgewy|jJX=$x&Izf#=y zrDdi!i=cvfGA#y;8O82$Ikvv{|0%=lb8laicN(NjFXS=!Asv}oq*6F6c+uGj;t+e8 zvA4mcd4ewoPzJICFvIZ~RdPY{@%?oC!TbzaI`sRI=dF<(h<n3h$pftYC{bN34X&HL zg5}RW#65-4_O~se6+MPs+pMe}25jQ<pc#DC%L@nlMQpw6H7T9|_#34!2oDi79PsSi zhz>5(!G#|ShUPy_Rv7A)lt3*<R0YM!(lv+ULvw*Q)TW;aaX@I$N!a5gwHg)9aVWLg zjHH~T*wDQgO&mkU8Z9j{=YJ_hN3x?;wunmyJnStSU<Kc`4F&6#c-jykVE@9r!pJ0W ze~XC6AodSIkt}xe%d+$6x%xK?s@#ikD1ToHn%+n{Td)bg*ziv;RUApZSUo0b1Eog0 zG-N<`L6R<a+u7hvglyq+jiwp#l1r%ZLl58M(SJQzert-1$yDrBPO77_Zt?VM3A$e( zg(z0aI6OU_pmv`2Fh9brR10hf^^BhLP#<64;|0eS0$9wvNIVq0%cYU#jX%R^UpQB{ zMlr?EWRGPTDzlTldn8LYvd^xR2Qv!llLsnLt9>)WGjb21N`zmvePR<8XBkv&{$u>| zb%d4P_gru+yebs9YgN^6PTA7SxNO<_6<WqKR}I|-^QniJ+DWmL)GnG9%R^;-ZAdVF zwkk3ckCpQ=&RxB9^L-W=>}0MYdlr$R*N-5X*EQXIT%IIza+HtZF_%OP{YW<paR!Fa z_v#LkcagN-GLp(xa=O@e@V{T}+|1amL<DbtZz4&rwm?Vw9FF!4*O~OdMKnB3P@ezI zrbM_tvy@+GT9Us#RTnY_rKq5?N?6S{u}a=N*J6=ivcIpiG8z--kMa-C8#^%>8g++9 zpq<vBmNM4Y!NEoPz7;OasTSKISSr9>jS`oe0h9=$bvKC7dYM?JOFZV{vii408?(td z{s*TF-?IeoBQ{9QKOyOQthI6?hZM{PN*hdtxF>X%IehZDLg=0|2=8W(Vr_(mxvFx7 zGJKTcUBHIx+)yF*Ix7Fu6!w)vhtRBwJTC#1p||vVZp+^*PX^TjY7(5B*FYTC<`0Uv zxCX{B1@k-EZ*OAr5(V-E!Wi^E8OSy_`6AJX^@=xiwnSiuDIbTk=TPKj9<yM_W?Q)@ z562Qr7Q!cxpLwfR8k54DcsP8o%GKO$L;}c>U$Z_-g_r!i!})y&*bR#CDY~4xUle!s zZ0{dFuc^?(Xd_y6cTOd6@PH8sO#sEpw<T$KnWopdOEY%EGx<o1cz4t=(|WhtO)+mp zglz?BM|Zane*tJ3TJ3zhlkEEn>c5Qizbh&6Qy^WqOq=wM!vyUKC{iOUkDNfLaK1L< zBQuIKtjenLLdI2OC8?y)z?Qah{OxaYWK!`J6rd66J$?R=IDP;u{)XYrg}kn$ziNK_ zDjg9uTYXHiP-DvDHIZ!Ye<2@V{zJh${$c!u&W9XF$oyCC!TL~fRh($G(E<sl><|WF zQS9>;-s<02KFsGGUYLTt_X~#cN;L2N2`&zimV?;GlJb%QAUe=Fwgw3n@pB0aBXsl) z{ZD;QPWwOyxzF_gz2{GR{Wm?|LLtG(Cv$uxycOAN2pE5al;AQ#&4aL&MoF^Gaws$y z(<`Bg+*ik57syM4a#iiyxwFFjFP(`tw&BC3IHBUMLIj346MU>t%<wWirojLYFft3W zB*Z7PPxG3+%AB%tR?K->3Z&zU6U;NF$vS~Iq~@~##sMVOFR{)*RMB$Nwprq?O6(+* z=0-~Gu|2d=wlH=uvDQl0xl;+goC>KlWZXVHORD6c;vmh02s*$|r*D8_rps=b%wzpP z8{`+$?TzQS6z|;OAFO{k`!GIy_u6jfClYc7=D&*y-rW?J`|M0D#T%15Ba6eN+2uzF zOEV$@yzpqSq}6p0i*}y^{mIfo#KnBx98DH=*}g9Ybvjik9L@I(wjl0(X>@#V^n`tp zBq&=?I!5j?p>de|ux=Y}PPDLHmhMOw6G5jS1gAIb<Wf7subP-BomCNUVM$qJ3`4_t z+HvNn%lU3pAG3{Dube9;IR!D-33vm+Ox{HSZcPz7huhm$MiB7~^-_^G;<*$^rvK7t zP{i-V-(t#rgJpkA`!5?QL+mp{-l}BCIdzw_!xDZv(mVqqt7mt#_T<|YMF(oS%Hi)= zOuS`~&3bx@q9V1t9r-rNj&P8eBrZ)@{0B}HOwOtYgbSIT9K_E4H}%xi%e?YAwa^+Z zAfKjRy+MF6ORd0I5hXr#spF$EZgR+--o@Zinz5^6ur^<hx}X$?cHyO*-!5Iu18A%% z+esVc>7a3!uf*uJYmO)aGN!oViqt&6-gJ!LMzV!PA2Mu^<I<hexz|B14~2f2={Kp- z-v;_Q`zW>7?+C2x%!huq*LuSB3V}fkFi+M8=Y2y2-S?FBrfk6|&(D_P@xO9a6Q8nk z`USeEi~5BhWb<aPw}rDZgJttXb6?Q~5m*{Zfn;N;Hb|>bqCYggFkFOyV>p6^zYuG^ z?dvCnoCt2op(KdIdA(I|rR277yE19=*D%AG!}lhVs!C?eGKin--#s10eM^S{lUUQm z<jI9RDuu$DKj;r8O(N&q6Yu8u(C~1Ad~nt^P*FrFLj19vF<q4Pv~#@b#MSX7(S!rx zgqXRXDjY<`8o{J;fsGMO`1Bpq{xVMNINF6E@R`O)?-}K3(oSlgZMglp;<+x~(?|t* zdbN{=Km1|$9#xbPAI*BPE;bg3#R<fYh>pG(muLI%;lnFYO--VM>0j{G;1OeEW5G`$ zAt8JF`$jv%83@*Ml|fGrH%^<qvB51n=}ws9Z(L87m#!OLqo8Ql+L8wZ1Slvfe&FZt zKVE7K+qhhCTWWA|c5z90hVLCWe0hE{^Sauf!v8Mir1yO+mD@_I!U)+1Ub2mdj6B<* zd`bTNYudMmic~aDDowv<C;&FtsQyqhtXN?yN4ni69==f|yT;3Et0mhA&Ne&d#SAZ= zP^M`b#cW5tdt+%3tFS~6OZ-JFZ<HoXOm-i}IT)?T;bszkSHWl^<i|i=43Z4M!9WP0 z^1_R2A=XyJrpsms#g<e70!6V2#x;!noNeZK#b_XLfs*vt0i_T$HJtT2s#I)y$##_( z8IaMZyd-UW^+Y#iZT*7ErT|AboIE*!X-fH!J$&ysC~|>_thRco^0}|N{?xBhlZVh@ zDdaip;iavn^3(A&8F%n;@q@;LJr+@(O(g{M$07gBsu;?cjSrw9|FK=_pZ=v&JoWW( zwgQonj+T}dp0)71Y1$DwT&#yNmp8?gdv7t5!B=)4lr;{2`#$}?cCmeXC~dC6g?Y;{ zr7+7kRmZM5!Or(0?d{Ivc~a}(<s}zziUN#YHcXcrjAT8{WjS;aX#VzjaP98y-aR=n zA4=sGycpzMbOt6A5xkGA42-9KYLE%KV}H{q`Q)(Kiz9qp5nbVSqAz??KQcBk(GmG^ zxvuCzl{KmU;ka?G${fpq%;~I)sLFbd<M}rFB^jLM?Woe@d9g1^)n!w~8vY9R>U-^n z%^&7>Mc5IJp91HmZGL8X3`ZZ-y+LP!j+gRDgW@IDc^Lp%STqfiS=bZ49Q!vK{NKb{ zIJmizufA8iw9{L6I$ccm>=Y>u;wTN`jZB7_?}IKJ_+t*Vm62mAgekvq1pw-y<JjT# zk^V(wDu*n}yDZ9wjH6>Zxj)KfD|BUVaQ+k8gR~xW%-a~gb~(zU%7}?VXU3Ezo{_v? zH9S`#Oa1^vg*%9rdWrvO#auDb#j}g$Mx>5BNZV|KxVpe6i_A3OVQ82=qtdcl{Ecnv zlWQ4#<&iL)@ZmIo^6{_L$=+U$zLIA1;qEScc`+d)9dKU=^cy^H8F>0IC!kGCOcY?S zb8{znEz9M%!&fP!>d)NmWR3jWS#KOI)XhDk3vAT0i@ymD4jy!^(Ar$~I@v-uxb^3| z{@8k_`0ozRh=4PqcsaU%HnX@$*7~&2x@4c3X4}As(C?q``*ue>e8r3$f3Lb&MMCo+ z_k8{;j!8Vk-$b0BZ10FyFGlf=WIR>A<7b+fie)xcY7%574l!_l9Ekoz(x5Wtj{*>< z|6`O^M>3TtN7@Oe&w1f*i25+3;XTK~9|L|~LNsKwfQ<Mg4R{rqdWt(0o#RF=In6`{ z5*sG}W@l=&Iau*Oms_xEK>g@d9W|->7bR<vMa|qV%6tsp6#bFGA(A_hb?mtVgrSRh zGhC>j=JT|A$W??sH_}4|pyciRV$whxH>xMze*CNc#+4`A<-1`w$Bwrj|1AvWscvM2 z)a#mk{TlvHyGMZM3-6o8m965!OpYURa`Ly|IQaNd{+;Z2wc?vLgO@9ViyxFvp*ptp zT^Q1zRpmAk5#R@BW@a{ceR#+s^0cQ!LP5cE)DuN+#XBM+e2#-jA=nEbVhOHJy^K*l z;V21RsUrqX9=Nz3&3Eljl{l3P6s63Ip=tGW=Hn2ldW(-Cn#}8*&{{WRuJL|vh7>R2 zj$4+R1%1|&W>5~ZhWcZhWh>0cs2~<Q5`+375ZQ9hv4yYk(0C_mmKf~ftUD;NEU`J= z)1r9&hx_Sdubnz7o=adgCavDh><y0q>YBs%d^GbfJl~@rgMTTCy?(ACO_+7?z81b* zJ*gv`KKgwe{&px-0W%D*QpGkx!JC)k3(YSHBXZbfZdyJ4eeia<l~HZb#mG>rf#Syi z|6#3+N(~&}i;n;-gwmIn2wFLg+5b=Lo^Dn~Y-*RxM3KBvq=213u7H@~;o*X^?!@;x zyeCZ;w~sp_D+pi@Cc^I&*%1*D_IF!J@BUhBXXB$G`@Y-&D<zGW<MMFlV`baYFR*-u zSysPI+H&>FuBN#lyVNAj&be0a>8C4-vRfBR&97LRAS`4=s1S!rNhiHo8VEw<0fXFU zC-I6E*^u;v0w6Ka2aYlcGFsdRnomy~#5e~w54bKG21*Yq(K%)JGkB6hDp%KZgYq<A z_cfBT^=ate&rG^1((F@xoxRb@EBCw)pOl}ZRRiz;r-HXPf5CnA6OsFs%PVfbP};mQ zxBEVRWum?HuP!<L4HRmL1z0IbYLq1nTI9^ogU}#tI{5yJl2ItjBbX5EZk3r#ca-6c z&&ZvA_q}wlYnH2b7chvlr&(wZ8??l%#&xDYi05N?_tAD!-rzn?a|Z4glUg55t9({` zZX8aUZ^p;Q+TcctP`lzQaI*r40JkAPuer#BHkFH(^K3yz!1&C}Otno%@LM=3#Cbb9 zoBI_&`Ft8ue?4zCbR8mmNxi+jU8K$wKVT|+Rji~^tnNObv)uk8TDX7Z37!QRdbQ<; zLa|zqX1o4)F=7tqNI~#kMWkG9L!sn?_cJB2?PPi#8-DrnO|`gl<#A}`6izTCbkh(p z4-ueF7wtuHln@qAyY<9YP2i75glD5_6D|NMq`eVW>lfMCQ6-*MshzalO|4>Gv@6)c zqc{<VBJEg}7w%RvgSpi1pi0hz>^r=^I;J<4C*K@YbbC4((cA_a!0qq!f{x19Rve&} zh;_g92I)Mlf@F7iAq7Hxe^8BCsHw+n!yLs$ld)qDns&jYc{2qaBG;dr?W5`oFjfJc zI>zDm<5?~h)ESH6+1Z>*g&4}7US99a@&^Y8?H6onU)j&-xxqsaqG-)$Q@E4;c6R1q z+jzut+;G6!a?^ZLVY9%~zjf{}E*K>4x4gVuaL0I`T6x?jfd%IivRSCx|5;LZx1E-f zm4%{OyZzS>&Td=}Gpgt%cUx>LDF<4<ULWl5_an!{p-mP1Q_ELnZWZuA2?sSEJp#*Z zC?dCF6FajN#@0&>2~km)tc`~p&znlmfp>Qv$Mrjzgl^nL^}4eb<Ht4mh?=RBMGIWJ zb$Lb-xDBNX7ahXd$|~j#tCBxo4OoL!w~F&-vgmuz9tH#|lRz$Hl5~Rr8t%K-j#Y|p zBX$q24xS#q)GBf~EDKqG5nYSy<++iptDSYi6_g#LLa-G6F7Q{LyXe4aw+VmZSOS8E z$&=J69?t&F_?d(STY<El?|#M4QBjw;4@$0YAq!5D_%9u)8RFcJU<xPAfup@KIRC`K zKdLFwd(&SX;H9OdZZY7M`{kI-T_JD}{-<&dPggT)tVxP1!^6;Ti`a?=29zrJ4wt)Q zi&pcEZfrtALKs+BPOE=ksfoaG-tKOZgVtq5$rRI-X9k=ONASkIxw%=f1F{15<F~sq zBK;X|%Y6^aH^P}d*V-3zSIwig|G*&$Dd{>b<((`-{0#7mB@|x41+#TMA1Aqf>E#ID zDJU}0zM5DOg{=F_d17Z+8SRS=;kTm@+o<uH1&n63xwu|(%j}M+z531-6>hPWUFQ=7 zyZtHRwA|<<5m>L4LLxb|bhaNvk)y}put;z+l6wIqqdI%-v$sfgWW8Gh!N`*p7}7$- zm<^iHeFLZ%HVV$rqbu2_DNhWgZKq}%(wQeh|4{Ow+2dZ)k24O4!DVUbaGBBT>Ft%Z z^)fdv^uwGH8@nGg7nXp7WjIS))lRm>@7YRI`Hl~4aP2_Q_uR{0bP~RrR3j7iPF}go zSn0DVS7+KzmCMK7a-19F>Q_@zicb2mzMm5UP#C$pC%@PEV-F8|$-k93uWoK?1vN*F z;>kr9Y6_94nt8aHO!ZUo@-jnyI;sb{8pTN}8Y^O}79cw2I;oGNG|%#1tr9WDRt)Lj zG_>|9s<<#E1@Zc6(HuC;6UtveSri+6!x}uhERP`#Z#(nq8Tcvbx;Mi@)01q7u+htb z^5Tzd*ig!ga2raJg_fcXd9Yg`?+_dHA2#hI`f^Ene-PA3dfaDX5%&T<_Mj8DomRxI zbhwl3?m_RFf&X!&voxBf+4FZg{NaZt`qrZUrPD;BVlB&5c{B}DI4E}akHjrOQ@?Mf z<(m7S$!2<NlSs?R>>VGQO%y0P1Fo*5410TfXJq)_HhQ8jG=VG4MUR~fxPv6co~?HR zj|e}o)Gj)r*L;qI16|T@CFL!tO1|eX!MjbE;w!jANECUw5ZSSNxwb3*RI=!G(tJ2y z^BqoTBrPpnciN8r_Kik~#<zk|Ww=&H_5ai;QSgD^TBF;E8NBgOh7$0J|A#LA5g>UT zewf&qw<<S<BZR}bs*tiW*5&8x+6$f5E1gA$9&)f_Nr2;2Kg3}^CnzoM?Sn{``!56p zR3wO`n7WqbN6D9;)2)ZUe)wxU4-H0$@j}s)bqS6d-W=re7BgAu<qmifMmf*dq{YEK zrk-D7#DM=wfk-Yubl$hjd34HqBg*??b%b<--R`8c*c4y-ohp4aA}Y$mgFLg!Us1s& zJ)!f?{kTOu#DQa2w#?XnX=aF1TY<OmmBOMg7Y}zi1{(i`3*6M<R6Z*Y%_|$tCq8U5 z27nOd%Wcoz$;r;{*pGh?tzO#b-^M+dRLCeFYb6e1WdMq`mWShw{gQGsYio>eAjs{~ z%9Eb(Bb<)oV(4R)<Ca_?_TfTpw4L|HJAGW+%zrdT%W#W!+=%>mzNZAt^9sU`%lKru z+52H(<+UopT&<nKgm)tR@UD**dLC9@e3xIIZ@g?iF1yqI`0>O0Kxbtgmh}iScw8rf z#B~DI2KH^pi_Q~@ECwxPjC5?Rj~rRgmxc8wEf0k5ZUKb!J&ZVWDw;Kj9`%f__-b3$ zvnY@0czGn7x)!mJ^+4b1Beo-T<B-@qw1s5la6}r4QsQ1JM3(z@mOxnn)rTYAp7C)i zqiqa<9P$$ixsxF}Qa2m?s)C4A)nBjLF)smEM)$R;2P!`Wkq~scGT7RGA+6=0SVE4= z3hvF#nG(dWqEj}*UdFsV(k+6fc50tqDflmMe#VtwLP382w#HHYe11u#$3;hSL%>x5 zPrq?=JKRAraKg;&WVKf3O@&R1mA?x#@A8j}QR)8)0tfy0aZa#p8djt`l}3<y1RkW( zxZNPxynmZlmPDSLl0A)Z)`XMR{m}ckFYL!?bV@7~+5V1Wf^4jJkEPFVK+|c@`Fxr& z1DFH_otRFUgAx?9^yH2z&DyhW3V5L6PDys<*!$X*FxVpP3>}d6SGs`}b!Zje(2*w_ zC2^e<`;sJ<VKkti`#Zqlf{4)0MHWIbWpCSlet(hQ0XvG@P18fFN!nRRQB+`@76j(Q zJJ8@cFH+^kW}FfYAD)AvPodoskvAg;XT#js#*dV#GmFzL22KK)1O<5tfD#mxl^%?8 zImNN}Jy20Lh;ZB6fl8v_L=S%HyAI)`;h(hZnkDHaDyPG7P&8b)+wLqM9nLYp0{G#a z#D9%kn0kBN?uW1+%$+gkhJ=L3IZ%TUV@GTa5!tm-j3bhs4B;Hhb1ytsMS5<DyN`hq zb9#k}+2!-i=kmeCOR33$mEf8L1)UrPKnV)U)k549up_q~NriPFT7imlXfK)8$pST@ z9^(L{$Fiv@+Hujaq7SUz^q{Y<&s)R94S(~f&cfL@4^m91D0?5gI^ph;8O<{X)aA^8 zFVXyyff2yum*`VFKmwRGOAP8YxFLShYcsdRLB+*`NnXE9b?eHYpdbi<5){;0E!`AA zg9Bthz!|ObK*jl$-QbMiC)8>OMelEa*t@WzPi29@0~T|7Z8c=ho%8OxF>X^Hkbg8E zX)`x2%W69RBzp*T&$5Z9-hBaQ5j8wu5xR@(qUdB?*Cp}ZrM8`H*vL5qnSEM<iMu~d z6yPK%sHFm+1O>HK)-B0t2U_Q+v<DTv>4!UTTovaM1n4L5+8rAWAJ_GeuG1s!xrLDC z>AtxkooqqmjjW9~MtJu@Ur?r#bbpqE^X`KSEq0`rE*ZEEif-3Xk^vgCR7nO(y!;k~ zS&cRqV9YhBV+Sw^3VK5o03|4B!CC;QG_*S;;^nAdLOBf*&HxRW5D*SvIIFj+!P}i= z;$Nmck2H&dU?VK95n`Z8m{3&~gc?5gf@`s0;dS&!b%|_v0&+tVEsZXTx_@f3odpfM zow`&D3gfu@(jH8*ySA<j3JPkb04PC0i<YGQB5%+DDt^?)9}Szq3jS&AFMb@DkWLr~ z&mBlF!@`B28Dj_}b}gQ4>PP+(_HJ9_wfYChIw?8F(wCWC0^WlW8m^-;PsMpNb<*#P z@DI}jOtOEX69SW#4M9Oc&3_aCB`D~G)Xq(D`}qCx*MxH%iky{cHF>yT;=_uxVIcQ( z&hZSen4Rpq$-J;JrVJUSy=3l4D|1Tu%6<M!W=9W1vIlkDm$t5l3nijWU%zbK5(gXu zm;?p=OceknDCl)*A)vC5ewsRT886h5H_};H5he`eGKROC8#Z#nOn(}3a!(`Nq60$> z*WdDk`%1DEtq1>Hph+70*|LQaxfm$P^s{bB4q*f^2@3j|C;&=O&`Hr^L4}N!lC>+` zfmt@dhMl65wr5YNmuhbS7F{-%+6XNT$05_SARcKlLVKYZY-p;PtCAP4$*EXS=q9tB zJ*IHOSSR9^v~3Iu3V&LR0-yv1om4FpRLJ?sZZ=f2vv!Gl%!bk0KYiY*U0^Y1$b%OA zIyYI@3;(oLn-4GTyUeT4t+TXZ9>AElPm}Ft(DJ(7lD3UOK|v>?04PC0Z;0HHcM-7S z#8BLsF8<<gj=V6CyKOJSb4pw&0X4l?`r#bcsmXk#mTJgZS%09K5sLKhf#)hMFjUj5 zkGI<EiMk~V>JStZbfOA?5)|}?t65klzpIynVs^{IirZfmn&;LwmC*m20T;lojY4Bv zZuMeD^M=q$=7=Zcu(YlVP!be$dMN-(P|(j(O~X2QeVwwiD2TtCGwLo9PIAxZMRbJU zmUAtOQ~nH|27kw+)#019wF8p8K22`hqR$-^6!eBD07_8MsZvf@r+Hte+}5^eG4i&8 zmW2XMj@z=JeNI;2Chcv3MAa>dGXj(Z1)VYlKnV&u)yfU)v><>yr=(@Y0^%2obz4qE zi#>ju{tE$;CTriluJZ;31^sLk03|4BDJh#%(x9Bmrho2Ai%Nk%dM_pcb|L-SX%YK- zi={O=Mza|@Z^ZQk1qJ<V6aXbCXsIgKDQPv5Hd&=L4_aii1{&d|-DyvPnnDQawKP3_ z0Ft1fGgbjmf`U#LwRK9G4e&X2twKqy;AK%-I0eXdv6zzq6ah+tf=(+1KnV&u9o04u zWug1$O>BQz{N<b!olJlTFcK7W+A9D`P|%s6g@$%c^jJ$>r{gsT1qHQK0F<DhGgT)O zT9%3ehy(?_X%qk@DCo_k#m?3_6$%g%6cj`Nl%Sv>R{;)!f`XQa{y%g6m%NMW<um{Q N002ovPDHLkV1kTqW99$= delta 57446 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 diff --git a/rtdata/profiles/Default ISO High.pp3 b/rtdata/profiles/Default ISO High.pp3 index 691141e2c..c15085093 100644 --- a/rtdata/profiles/Default ISO High.pp3 +++ b/rtdata/profiles/Default ISO High.pp3 @@ -1,19 +1,18 @@ [Version] -AppVersion=4.2.84 -Version=322 +AppVersion=5.1 +Version=326 [Exposure] Auto=true Clip=0.02 Saturation=0 -CurveMode=Standard -CurveMode2=Standard +CurveMode=Perceptual +CurveMode2=Perceptual Curve=0; Curve2=0; -[HLRecovery] -Enabled=true -Method=Blend +[Retinex] +Enabled=false [Channel Mixer] Red=100;0;0; @@ -42,19 +41,6 @@ ClCurve=0; [Sharpening] Enabled=false -Method=usm -Radius=0.7 -Amount=250 -Threshold=20;80;2000;1200; -OnlyEdges=false -EdgedetectionRadius=1.9 -EdgeTolerance=1800 -HalocontrolEnabled=false -HalocontrolAmount=85 -DeconvRadius=0.75 -DeconvAmount=75 -DeconvDamping=20 -DeconvIterations=30 [Vibrance] Enabled=false @@ -68,6 +54,7 @@ Enabled=false [White Balance] Setting=Camera Equal=1 +TemperatureBias=0 [Color appearance] Enabled=false @@ -82,19 +69,19 @@ Enabled=false Enabled=true Enhance=false Median=true -Luma=0 -Ldetail=50 -Chroma=30 +Auto=false +Luma=40 +Ldetail=80 Method=Lab +LMethod=SLI +CMethod=MAN +C2Method=AUTO SMethod=shal -MedMethod=33 +MedMethod=soft RGBMethod=soft -MethodMed=Lab -Redchro=0 -Bluechro=0 +MethodMed=Lpab Gamma=1.7 -Passes=3 -LCurve=1;0.05;0.5;0.35;0.35;0.55;0.04;0.35;0.35; +Passes=1 [EPD] Enabled=false @@ -108,6 +95,29 @@ Enabled=false [PCVignette] Enabled=false +[Color Management] +InputProfile=(cameraICC) +ToneCurve=false +ApplyLookTable=false +ApplyBaselineExposureOffset=true +ApplyHueSatMap=true +BlendCMSMatrix=false +DCPIlluminant=0 +WorkingProfile=ProPhoto +OutputProfile=RT_sRGB +OutputProfileIntent=Relative +OutputBPC=true +Gammafree=default +Freegamma=false +GammaValue=2.2200000000000002 +GammaSlope=4.5 + +[Wavelet] +Enabled=false + +[Directional Pyramid Equalizer] +Enabled=false + [HSV Equalizer] HCurve=0; SCurve=0; @@ -116,9 +126,6 @@ VCurve=0; [Film Simulation] Enabled=false -[Wavelet] -Enabled=false - [RGB Curves] LumaMode=false rCurve=0; @@ -134,12 +141,15 @@ DarkFrameAuto=false FlatFieldFile=/szeva FlatFieldAutoSelect=false CA=true -HotPixelFilter=true +HotPixelFilter=false DeadPixelFilter=false HotDeadPixelThresh=100 +PreExposure=1 +PrePreserv=0 [RAW Bayer] Method=lmmse +ImageNum=1 CcSteps=0 PreBlack0=0 PreBlack1=0 diff --git a/rtdata/profiles/Default ISO Medium.pp3 b/rtdata/profiles/Default ISO Medium.pp3 index 889911a85..0bd94097f 100644 --- a/rtdata/profiles/Default ISO Medium.pp3 +++ b/rtdata/profiles/Default ISO Medium.pp3 @@ -1,19 +1,18 @@ [Version] -AppVersion=4.2.84 -Version=322 +AppVersion=5.1 +Version=326 [Exposure] Auto=true Clip=0.02 Saturation=0 -CurveMode=Standard -CurveMode2=Standard +CurveMode=Perceptual +CurveMode2=Perceptual Curve=0; Curve2=0; -[HLRecovery] -Enabled=true -Method=Blend +[Retinex] +Enabled=false [Channel Mixer] Red=100;0;0; @@ -43,8 +42,8 @@ ClCurve=0; [Sharpening] Enabled=true Method=usm -Radius=0.7 -Amount=250 +Radius=0.75 +Amount=200 Threshold=20;80;2000;1200; OnlyEdges=false EdgedetectionRadius=1.9 @@ -68,6 +67,7 @@ Enabled=false [White Balance] Setting=Camera Equal=1 +TemperatureBias=0 [Color appearance] Enabled=false @@ -81,20 +81,20 @@ Enabled=false [Directional Pyramid Denoising] Enabled=true Enhance=false -Median=true +Median=false +Auto=false Luma=0 -Ldetail=85 -Chroma=15 +Ldetail=80 Method=Lab +LMethod=SLI +CMethod=MAN +C2Method=AUTO SMethod=shal -MedMethod=33 +MedMethod=soft RGBMethod=soft -MethodMed=Lab -Redchro=0 -Bluechro=0 +MethodMed=Lonly Gamma=1.7 Passes=1 -LCurve=1;0.05;0.15;0.35;0.35;0.55;0.04;0.35;0.35; [EPD] Enabled=false @@ -108,6 +108,29 @@ Enabled=false [PCVignette] Enabled=false +[Color Management] +InputProfile=(cameraICC) +ToneCurve=false +ApplyLookTable=false +ApplyBaselineExposureOffset=true +ApplyHueSatMap=true +BlendCMSMatrix=false +DCPIlluminant=0 +WorkingProfile=ProPhoto +OutputProfile=RT_sRGB +OutputProfileIntent=Relative +OutputBPC=true +Gammafree=default +Freegamma=false +GammaValue=2.2200000000000002 +GammaSlope=4.5 + +[Wavelet] +Enabled=false + +[Directional Pyramid Equalizer] +Enabled=false + [HSV Equalizer] HCurve=0; SCurve=0; @@ -116,9 +139,6 @@ VCurve=0; [Film Simulation] Enabled=false -[Wavelet] -Enabled=false - [RGB Curves] LumaMode=false rCurve=0; @@ -134,12 +154,15 @@ DarkFrameAuto=false FlatFieldFile=/szeva FlatFieldAutoSelect=false CA=true -HotPixelFilter=true +HotPixelFilter=false DeadPixelFilter=false HotDeadPixelThresh=100 +PreExposure=1 +PrePreserv=0 [RAW Bayer] Method=amaze +ImageNum=1 CcSteps=0 PreBlack0=0 PreBlack1=0 diff --git a/rtdata/profiles/Default.pp3 b/rtdata/profiles/Default.pp3 index c4ea48b60..227ee2e6b 100644 --- a/rtdata/profiles/Default.pp3 +++ b/rtdata/profiles/Default.pp3 @@ -1,19 +1,18 @@ [Version] -AppVersion=4.2.84 -Version=322 +AppVersion=5.1 +Version=326 [Exposure] Auto=true Clip=0.02 Saturation=0 -CurveMode=Standard -CurveMode2=Standard +CurveMode=Perceptual +CurveMode2=Perceptual Curve=0; Curve2=0; -[HLRecovery] -Enabled=true -Method=Blend +[Retinex] +Enabled=false [Channel Mixer] Red=100;0;0; @@ -23,7 +22,6 @@ Blue=0;0;100; [Black & White] Enabled=false - [Luminance Curve] Brightness=0 Contrast=0 @@ -45,7 +43,7 @@ ClCurve=0; Enabled=true Method=usm Radius=0.5 -Amount=250 +Amount=200 Threshold=20;80;2000;1200; OnlyEdges=false EdgedetectionRadius=1.9 @@ -69,6 +67,7 @@ Enabled=false [White Balance] Setting=Camera Equal=1 +TemperatureBias=0 [Color appearance] Enabled=false @@ -81,7 +80,6 @@ Enabled=false [Directional Pyramid Denoising] Enabled=false -Method=Lab [EPD] Enabled=false @@ -95,6 +93,29 @@ Enabled=false [PCVignette] Enabled=false +[Color Management] +InputProfile=(cameraICC) +ToneCurve=false +ApplyLookTable=false +ApplyBaselineExposureOffset=true +ApplyHueSatMap=true +BlendCMSMatrix=false +DCPIlluminant=0 +WorkingProfile=ProPhoto +OutputProfile=RT_sRGB +OutputProfileIntent=Relative +OutputBPC=true +Gammafree=default +Freegamma=false +GammaValue=2.2200000000000002 +GammaSlope=4.5 + +[Wavelet] +Enabled=false + +[Directional Pyramid Equalizer] +Enabled=false + [HSV Equalizer] HCurve=0; SCurve=0; @@ -103,10 +124,6 @@ VCurve=0; [Film Simulation] Enabled=false -[Wavelet] -Enabled=false - - [RGB Curves] LumaMode=false rCurve=0; @@ -122,12 +139,15 @@ DarkFrameAuto=false FlatFieldFile=/szeva FlatFieldAutoSelect=false CA=true -HotPixelFilter=true +HotPixelFilter=false DeadPixelFilter=false HotDeadPixelThresh=100 +PreExposure=1 +PrePreserv=0 [RAW Bayer] Method=amaze +ImageNum=1 CcSteps=0 PreBlack0=0 PreBlack1=0 From 095d33db09d4bcc3cd9002d0ba4828f4e1457258 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood <bugs@londonlight.org> Date: Mon, 15 May 2017 21:44:27 +0200 Subject: [PATCH 17/32] Prepare for merging 5.1 back into dev --- RELEASE_NOTES.txt | 46 ++++++++++-------------------------- rtdata/images/rt_splash.svg | 36 +++++++--------------------- rtdata/images/splash.png | Bin 76484 -> 80104 bytes 3 files changed, 22 insertions(+), 60 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 51dd4c0f3..84f05bba5 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,11 +1,18 @@ -RAWTHERAPEE 5.1 RELEASE NOTES ------------------------------ -This is RawTherapee 5.1 stable, released on 2017-05-15. +RAWTHERAPEE 5.1-dev RELEASE NOTES +--------------------------------- +This is a development version of RawTherapee. We update the code almost daily. Every few months, once enough changes have accumulated and the code is stabilized, we make a new official release. Every code change between these releases is known as a "development" version, and this is one of them. RawTherapee provides you with a selection of powerful tools with which you can practice the art of developing raw photos. Be sure to read RawPedia to understand how each tool works so that you may make the most of it. http://rawpedia.rawtherapee.com/ A great place to start is the "Getting Started" article. Click on "Main page" in the top-left corner when you have finished reading that article to see all other articles. +While we only commit tested and relatively stable code and so the development versions should be fairly stable, you should be aware that: +- Development versions only had limited testing, so there may be bugs unknown to us. +- You should report these bugs so that they get fixed for the next stable release. See + www.rawpedia.rawtherapee.com/How_to_write_useful_bug_reports +- The way new tools work in the development versions is likely to change as we tweak and tune them, so your processing profiles may produce different results when used in a future stable version. +- Bugs present in the stable versions get fixed in the development versions, and make it into the next stable version when we make a new official release. That means that in some ways the development versions can be "more stable" than the latest stable release. At the same time, new features may introduce new bugs. This is a trade-off you should be aware of. + News Relevant to Photographers ------------------------------ - RawTherapee supports most raw formats, including some unusual ones like those from cameras using Foveon and X-Trans sensors. If you're wondering whether it supports your camera's raw format, first download RawTherapee and try for yourself. If a raw format is not supported it will either not open, or the preview in the Editor tab will appear black, white, or have a strong color cast - usually magenta. In that case, read the "Adding Support for New Raw Formats" RawPedia article. @@ -17,39 +24,12 @@ In order to use RawTherapee efficiently you should know that: - All curves support the Shift and Ctrl keys while dragging a point. Shift+drag makes the point snap to meaningful axes (top, bottom, diagonal, other), while Ctrl+drag makes your mouse movement super-fine for precise point positioning. - There are many keyboard shortcuts which make working with RawTherapee much faster and give you greater control. Make sure you familiarize yourself with them on RawPedia's "Keyboard Shortcuts" page! -New features since 5.0: -- Pentax Pixel Shift support, to automatically combine sub-images from a Pentax Pixel Shift raw file into one high quality image. -- Support for processing any sub-image from raw formats which support multiple images. Currently up to 4 sub-images supported. -- Dynamic Profile Creator to automatically generate per-image custom processing profiles by merging existing processing profiles based on image metadata (Exif). -- New command-line executable "rawtherapee-cli(.exe)" to reduce startup time for command-line operations. -- HaldCLUT paths are now relative to the HaldCLUT folder as set in Preferences. This enables you to share PP3 files easier. -- Auto White Balance now has a Temperature Bias, letting you make the automatic temperature warmer or cooler. -- LCP correction works for raw and non-raw files. -- LCP distortion correction support for fisheye lenses. -- Certain tools are now hidden or disabled if the loaded image does not support them, e.g. the tools in the Raw tab are disabled when working with a non-raw file. -- New zoom levels for the main preview in the Editor tab. -- New Fast Export option to downscale the image before processing, to increase speed. -- Custom crop ratio. -- Automatic monitor profile detection also in Linux. -- Lens information support added for Panasonic cameras. -- Support for lossy DNG files. -- Support for compressed Fujifilm Bayer raw files. -- Support for compressed X-Trans raw files. -- Support for Sigma sd Quattro DNG raw files. -- Added DCP profiles for accurate color for: - - FUJIFILM X100S - - LG Mobile LG-H815 (LG G4) - - NIKON D300 - - NIKON D300 - - NIKON D5600 - - NIKON D80 - - NIKON D810 - - OLYMPUS E-M1MarkII - - Panasonic DMC-GX85 +New features since 5.1: +- This section will be completed when 5.2 is released. News Relevant to Package Maintainers ------------------------------------ -- No significant changes since 5.0-r1. +- No significant changes since 5.1. - Requires GTK+ version >=3.16. - GTK2 is not supported. 5.0-r1 was the last GTK2 release. - Branches "master" and "gtk3" are dead, do not use them. diff --git a/rtdata/images/rt_splash.svg b/rtdata/images/rt_splash.svg index bb71a3c4a..d860798bd 100644 --- a/rtdata/images/rt_splash.svg +++ b/rtdata/images/rt_splash.svg @@ -17,7 +17,7 @@ inkscape:version="0.91 r13725" sodipodi:docname="rt_splash.svg" style="enable-background:new" - inkscape:export-filename="/tmp/rt_splash_51.png" + inkscape:export-filename="/tmp/rt_splash_51-dev.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90"> <title @@ -577,9 +577,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1" - inkscape:cx="354.28099" - inkscape:cy="103.21" + inkscape:zoom="1.7051773" + inkscape:cx="290.94671" + inkscape:cy="112.00674" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -1022,39 +1022,21 @@ sodipodi:role="line">.1</tspan></text> <g id="g3712" - transform="translate(190,16)" - style="fill:#000000"> + transform="translate(-2.9910244,22.7661)" + style="fill:#ffffff"> <text xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:110.00000238%;font-family:sans-serif;text-align:end;letter-spacing:-1px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + style="font-style:normal;font-weight:normal;font-size:40px;line-height:110.00000238%;font-family:sans-serif;text-align:end;letter-spacing:-1px;word-spacing:0px;text-anchor:end;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="559.0896" y="46.61301" id="text3690" sodipodi:linespacing="110%" transform="matrix(1,0,0.05240778,1,0,0)"><tspan - sodipodi:role="line" - id="tspan3692" - x="559.0896" - y="46.61301" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end;fill:#000000" /><tspan id="tspan3696" sodipodi:role="line" x="558.0896" - y="71.363014" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end;fill:#000000">candidate 1</tspan></text> - <text - transform="matrix(1,0,0.05240778,1,0,0)" - sodipodi:linespacing="110%" - id="text3702" - y="46.908493" - x="556.10699" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:110.00000238%;font-family:sans-serif;text-align:end;letter-spacing:-1px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end;fill:#000000" - y="46.908493" - x="555.10699" - sodipodi:role="line" - id="tspan3706">Release</tspan></text> + y="46.61301" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;line-height:110.00000238%;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';text-align:end;letter-spacing:-1px;text-anchor:end;fill:#ffffff">Development</tspan></text> </g> </g> <g diff --git a/rtdata/images/splash.png b/rtdata/images/splash.png index bad884e4596f5e68f5274e5d92ded8e9c7e5aae5..11d8b1889ebcd375f8eee6fe0f29c465961283aa 100644 GIT binary patch delta 15779 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 W<<+8Gv~>s+_>hx=NS2Em`~43Nw%$nq delta 12130 zcmX|Hby$<{_a+7DE@=k?q@+8CFkpib(jg!rAvF*XMt66Yq##I1gOmfLk?wAg66x>! z{I2V_fA?<JbMABB=ef^$&+aK!?-bV8!CS-*BR~(nay{C-B)udk{oYOpGjWU@p!tDK zid-@RUv{0lm)$<eby|cgEvd4COlxy3z9~B}nPFo|mbsVLr@|o#uI{j2*!H8>;Cs5c zzB*YH2|pEXP;UOX<wg3H`c=ElW7Ce;t;ba~$+Su~-_)_&sQA^m=cY{F!-L<B@d;vh zDSq{%QOn7o!1!A`y;R802M5NwmP+p#xHWs6q3&xw#L37mIOrB0|8nbCCe_TH^7Qz2 z&ghHt-5T;fum5-#U}yW{J>BYJqiLUjh2co$Y2q^h$13GKNx|^!mNvhPhq_S(QmJR= zoNZWb{Ja|1sx@=IKQHBZTRuMj=_84dVlJ25qG5V%v6@o)!^`4McljK>tM9!D^h7SB z3EC3v8{<Buzm?sjHjf0)TbEKQRwlkl(oeKHhZgbAL{g08nND!kZ`^nC$GyTRz{<hE z#$nr~P~D_j2=P9%x%~U|oA-Uv_R|Kx_9fwsGBi-2g^lP|7mGDxTUf-}IR`yL=G9K< zWlVGEO_bEe*YJ_>2e;7zOXN@W$UumWg9HsKhQ+L@b()L^gKf;-Un`0yQQ|mamytGD zo&3pk^6zz;tP5`CK%;ka#%HNh6oqBw_K9#!GIQi7W%1u<6^Hi(#(!S?+%q$M4gR`k z;lPRi;&0g-#)necxy_v3^h+pWLTUDbfN`jjVXp<qLuEB-sAA!uIaaQPmYlC$*%#(5 zr@=R^n?St}vrWVY?4{M{ykUeJuK|ZL9U0DGTNXCdTU~ETm>!-aJ%46?C^qFLx{0Wi z(j>JrRee<N9r_E~hTv{v$!!JS*vxNRCybZoyNNssW?Kwnq`BipZuKF8kORS~iIuh9 zR?l}#h0y9l6CCdUoG@*VMSVJa$V>cLZ2*0&b<M;z(w+>})dxnvAHaCPi2=ogAM#zB zIZec97c=4s<vxK)o)}MF*Jp-!C>(>wwEi8REq^<H!r^t?LG<p?g=gXK!3UMxy=QY9 z%@so>sbQfMHhQG6N`$+Xfs4o_v2V^^m+r4P$YkA{Ala$e6nxx${k{a#C!?kzv&~7I zRA0IMv^fm0W;g322B_nIJ`~u^X!98OFGqwY1SDZHMtMMr@+(AoL-f8_n&*FFi*6d1 z&ha@*I$^RpYz{hX#;@|eB3Zh(8;O8MHi!ecNWbywU{od%JVUgOJQX<s$wyYrcmb^q zd_;kL*O-l&4N146V&k%=nqy$i|3dL7$mK5D4D*hbEL4>G0qa`9A>^EZ@_3NjrYwdm z4m~6=@0X2vO^d5bpT!M%T)vbgovgE#E@aMR|2ZG@*`5dATjWcz{ftb>e&XywG7jTN zi~)C<kR3T9iTL?#?vS0a1Q!%fgs{`a30&tJr9(quKj(VMkBwdb#k|)ss(7>cq;s$U z82fu)Z*|{ZZ_I!v!%F`sJsmXby`R3TQzpi~BoZ4Dnk;kzkSv}Z7Cu!Je@CiV=eP#q z>z^Kxei}^X&P9pFW*fmltd&hG{3D<rhp0}uXNVCo_e3k1^`P-@o%h!tF__%2a&`D{ zv%2g9nj1M%JXdG$=o!mCub0!)F)|&lohs|O+B#AnPXS0ljXmZeH;K-?e6)K0AGY1) zBsUi|<xBA<EB=r^(FvaMTiY3{bIJoTA9&i{3c)L5J#6z9(;Z~o@%HcgNqTRzs@DhE zG|Ul*rEGFZOXVPN;c71wNF`GFX$`cK!?6P}xdJ%4ty#VF0<zST*Hip=__B~F47q8g zaYs6ZvsmlfD5)82dK~NvuDaZFj0ZzbE+!>h5?H`-!_Ld|MQwnOr*lzD_HmPn%ZKl= z@9@!5%IL=H?09^Wgtvjn3^n%;FOYs_2#&IPaiHKv|HwkY^O3!;?m~R4Z6M9^4i~40 z<;LfG+m%}f&8vwlktoX0Mq4eQ5w(l_jCyQI3VM9;X4|Wa^6@PV3oDYxh1^{G3M6q2 z6o8F@9ZJc8HNV|4*U-?I(ZC>i9ikl$w1MrM-LY6#E%oJygOaiXd#d@TBj7QFmhL}( z74?OB>kP<+VUq2WaQdq(5DP#fA8MzaB686IF-EL4;D(N*#6Ks7?YZ;zlI4#JJ<&Wy z5U)d;6!^}p^C*UValNa5*Hi^(`<Zr$l02Ja?FUUe@ztVx{K?V83&g@Vo~bndeNaGM z>d&O()ZHtU)ZJXOKBdm4Ohmw22FEvmgG{uxyIvQM_ODUCjf%QDvuD#?6axER&V^(a z<dWLR5b_M%>cj2qczv<)(Yez#5PFy^PVvp{H@u@w&fh4(|EH3Y?SfqFtxxIiB!iGL zc}RuG#(nN|C7a6{hbA0+&h8KjCVdIz*D&tXbe~-&8YcY+DJcXLe&h{;wX&q6&v4*y zfMA-^2!@~DBkc2?Nwk7&8PoZR_-w<sQF|w>K8WPH$%&-&7_s*u#zG(JgQ!^Wbar0N zy7w7QS00=`xqKZ}wI`x-4)HtdNB{HqAz8Yy=O*u&`P8<Pprih0O(<rz81ciof>@31 zkT5vANDl`}#)+7G>u1Y2f4T+;_6UUXVaq)=41AXqw=S~1RlNI}kV?Xi3ZHv#rinky zPV8G9V<fTENIBtQyaaQ*uX}8z^-Wi`AT^Lai*KB#g@gB`207e>nVTKJvLCxU*OuC~ z&b&S*V{K)X<%UBt-o}H^<q{n&i!&AEg=6UYdAKJvfC9m)@hTjLRl+`~a-l6ZChLY% z31&p&Vso@>^l@`nY9Vj7uM3g8KGhkfwk!@h(d_GvARly@5l(ow|254_OK&6s6DZ)3 zO`hYkt_~D&wy-`#Wr*qf?~3}5aoW@r^~r3!O{;;wM}=%7${{kUPG!n}{VlphFj}*H zi_X+obrDn~<u>Oa>~mgS$q<EkM#}j890k%sT!XPK1;bcY4ypuL0M@`7!k1u9TJHYl zab)iPo}lgaXn4kPdh~+j{P<(`+|C~t^U)XdU_1cy!%w&PA>Vv(PT-e4SYqyqziO6j zj~0x<@6(I*%9JxWPYe57kd1GA%Cj(9Q`kTVDS}$zEFb%_W8+p?T<DYzM+Ru#){FiA z8Gwwm7f-|j9S@Y~?Tv=X`WYh04(6Whh~PQk?EO=Ks4ZB;gQ_1#xM&I$%r4L^Cgm4b zt>$C#z;g6uB8fR$IBl$n|2Dt4!CxfYDzmiP={vHCVF)0Z$kyaQ+n2DBE)@BBD7(_5 zgE(<5i5nRgYzi&QROCFOr$p~tGrbu#>ZvUYTVK=5pu|qB6kI3d9cD=B{uQV4q+@3G zs}7~S7pujVCQ<&_yl{elypqI@-q+La28Y?N(eE0X@+r;hF3|*ChBO}DGT}T}Mw>ih zj+o9MTg-NY0JYj7OLjeblVlSg$v1Mvt`TfCC)x1>!d;a<iK)_Jc9hdyUNes+nAuo4 z)?D9C$SB;oHlt^kSHFk|amRb<eNP}#|J*qi5kMv%NCLYl=7o#HPJ;k&<wU?+X5AQ_ zw{n^9uLIqrm6Fm}r@nG>XqvRgo{iy#q3q6_$!Ogts=9XuOwyg+@aNI~5Qlz&XvF!o z<OsuRCFH$jpKVSJ!Y5F%wzskwC+7bCwlMN+kNr(yaRsLEo7|W>&6y(R7w%J`v(8fj zpF<RW(uxa|LK^Ll?iyWQ#dZ8xtHz7H4_jUL{F1+@%Up%I|FlO7J;KOiiOgjBp4=pj zLkvc3wU{`|Ym{fT23o=rMPdm!7b4_j{s~VRW!r3@RzS*tl7o_UE{E!jYeKCR!}FE~ z(>3C36JA$I*3aDDR8AJ!V1a$D3S-HZo{g4voKU`dbY<G`?NMjUEHXSU9b3tGtT9n$ zd(WR>7pn?CHw+yyfQ-(*={@9jV?Ar#IWo!%>(1#PIlXh^gAF4SA-W`p;%z5zODq_q zyr@xaJfNgkxqax?GMu~?QiYb4BO@iFYk5mvU5i*?@mS(5r+Sh7_-%^<FTquf|L0_B zY=kDCE;PAfU7X#{wGy4G{Ko#bihx{Uw={3I3OSNgrbvuvP$4_%^`*RgsTK<=#E1%p zBCA#-m9Ah92boA0JrDv5mYEkAPSWDw3S%t_CxKa=Yh<@k*bUnGMRHKY!_bF(tj=|H z?(cp9EM-3?+fKdOKWRx=dyq+OKR*h0O&TpMW}p=1>+_BC$68l}$KD^1N5jmu_-;}& z3{BFP!R?Qo^2%8Y9lw&lFGMQ6{u1+Sk&F|&uSm67=KK7MCwmA!D(cN>D@C!ny`HDP zCr=o*eh=Bx|6L(Xl1*^vuolmeF8;*;#wzQZGR6r3ZRG%BD+&t~VOsmivmpH>wZa1w zXWgMxPk`M0;!mB)>UAjTlk+F#zOX1+-L^a}fIdV>8Y#Cjh{Py~9V>rIvd{oPvh<FE z^9jgTf1!uO3LuuAi6+s@svjjFtV$LKY9fNGGU$pEwjdeyEU|bPg}LEX5PJiUW4fCi zK+5S$IZZc@7f@+=so$U^a-KI&chfnX|ELryNRk#eg^gUZy#8X;cb)Z0%pRWNYW)f- zXj3#L0Ys~A7aGPNJ+yeVM9%r*5b##G9vh{>I4I+}kO&Z0BS=;dX*LQ<ua&gKvCARP zuoX+7vOY^R*QLdQ7S%s~dxP#gvH9(Z*i*wnJR;RGyF!upbw3uHBpY3VWuL0pgCg9c zT#y|!k~t?uv1pMjK?1<4Rp-aLl?=j_?m>#Zz?Qs4ig6^sU+Xl>$RcYTHMEjQ2dY<8 zMnAjJB9`yml1C*g#LH|O+;rTT(0er(B$0pJWUY)}4beYx3)(!I0n@fG;^p{-<^~$5 z-C>E+mCcoD9a>NIvjrzcgvCFa$F`5gxw<0(pFHs+ll33fFx`{!*{v+;<JAp-&6zDA z=7U(p#NBKPStM42Lgh|&|B#LayoS)3_1PK#!N*oUmnVs)I;Qm+Wke=b2&aS1POQVW zE9tU`IX&9RQTMjG{PY_}zRl-C>EZRp&Lu2a{2EWJ@RW)IDVNOfy6*nIjD6Sz_l~K) zJGo=N|2b;$H}M5W&g9I4M^k>`N>%_Kvkl<%)T~&<E4X|~Tm5Ap7WvRXGaC*!hJ4sA zBA=^5r(DbAb#dFbp)e7Oz1Pmy-sS*&p$$R!A1SZ!=a$N1A2kwAsVztDx8CZc!HXp6 zfLMaQvuzZ~O>n363LNfOqeOtnRWJS)hggA~Lgk=W;-4TI{jR(k@>RgD`~O8XY)sKu zNLy6oq-vx>I+sm>6eg|8Dm>F2LP&6SH*xaThbxS4R;c)LFRh@blrL5DKimmYh?uF~ zy%6P}mHj@Z`~DMuy?=xUK32+{<0JT5Pj-KlEHkY6$Ze=ipvOVrXJz`^P+IFPZms*P zSE^-?T!jk29386=Rh<GiOW+pdt*qXw?$LIBBqg=3DRp#{Z^`~kNrZEJ4PwKRzN7Jb zjpNe_z9UOp#WZYEYB?zy7*TkVk-~bFy@Fy#1UeZ*6*#-Ls7qXar$kH~xZ1?d{^MV8 zL)z)q^zL*60mP-d1HIk^F=d`|5~Fho;;s2hr&t-`zj(kpuNAOVG89zkOC4_%tR%kZ ztCDCbB<E`E2E8Kf2Vj#SXj!Z<w1&-~S~UBnb*cNAaP{Ml5vP31-Q&ZuqiYc^Pg;Ep z{JPlO9cbP$-V9{rX1B{e1t4>6hb%eeuL}jXq6WWJ5e<CkUQ}}%V#+QRG5ho?CbJAy zIwE!6+Y1nof1Gi4BxAkL3+K?x4<d@B;Di+d)RG6;Btj)P@{HIK`!Q#oF#?!-Bjf2m zc?WS~`?y;?Hv6TjACNT2(m3b89pN>|H+|c@yk2H}3iE&&3ayKC7w1J1lRs-pB0;Dg zWgvtc6EG6=;NFT4tTG})!9t+-kICx8{UF7s)tFj<L>0F7ND62nF3Vd(DpCL*^jFf| zFBWZP(&KOzg!T+b6(m1=BhQ-1k+b&vIkq51M%j_dSe+B*(t!wn#|BW{Z*4=}p(FWu z7$Ru@+@{9DDtLd3TEr~j8)caaN&Dln``DR|zb$j&c_dU~AOp{2G@CEfN<x0*vyT=j z$Rxpp>y?>C>-#Kh;{^~~;kLUOZnR42LxY|*%@RBuVR?%bzdOP}<^`-lIMbQ=>)f=) zR6LW}*HVnl!KFC%nxrDgUO=}<cSHcyR;Dcpm}SPqeRx28;O<;t3k@i5Q>G9O+!fNz z`baUu>0CP3w8l8a(dJBS7p}aMzk8&@HoDKRQIup6GN4xTwB9c_GN<qmszLS6z&9Zk zGRuL`a>U>?e>cj@?sq0N9$6QTxbD<4ZO_;;$+_s*`Vw9xGFK1X1&Zs0y?w95UD3Gs zwp<OW;^#<9@VOK6f@Zv0oOAB-@rSsf<WTR6I{F7$C3e$j+Ii!*n|I5<=-ph^;zevg znBk&qvtajO{Jo}w^j$1{LQXoBT0yvTj|2~5wRbaTw-yt)9o0sgU2ltzXBdg+Pv%Z{ z0GEr*l2Vhv-BgS;eW4T(o|P8p%-n}fz$7Q735#ghrhygB3oVvOr3d=G(!}Eu{8at& zVPhvgN4M$l2(Z%`(ox0xBs8?l)UO8qBGYy|j2L#^pdsXG2Bik;Uk?#<UZhqT(~KkF z@YU}f21IS{$)5z3#UB*K?nnUIfhlQ!#ye{#3+RA+fUKcR@Q0KiRW7f6FVTL?nMMBK zkL7KJMtEomg>#51i7k+zI5%8Mvi?-!ev0JMrAK-erY1%S<>;@BD(v`v>CK^4!a_@0 z@FY=a^AlrYVhd-4y3MtUKW;)%swARFGJ?b8wV6tLn;#ade7{0VZ$~sqgywN1e*t4r z?lCt>LcaZn^pOP0U!|q#vkzi*E3Ih}ZXyDHm(|)I9A$$Tu%GZgC`DF$z9#*8jd(vK zD-MDG{%~I2huq#jd{~3ACq0kuG~W5GNJ>7csE5F@_v=U-S!V5b@6$`z@J>e@>C^0v zy~%ah{ox5IT9M^j!P+t2Eu~mMv<<KJ67Hn?p+f_gvHnX*MSwcp!bR4vkBLNpJxK@) zw&v&wn3?olI|VkU0>`R~mKb;frUGJC!UNhlsY-O?7AR*@sH;Pxb&vyr;6w?a0xk#c zxtcL3P^-9mm5rK(uQ?u3F5Q}O_lH`g5F<?V5d(+l_>-kMn=b>Yw9S{ogZ1I^x<t8p ziv?Oim0<#^vV?~%^40GN;zSQSVoB=GA0G)USK`EOPRK~9^<CseE2=9>5OKlo2@P0D z(Vv%y3Bt#4**}|l3pxk8s2Vo2dw+H|#YOsugF~@T=EP~mYVy|*XawJ+HBd1^Z9+&i z#%S}c3mA1dvumNL!k5QB=h#a_s&(Dlg|jjekG-jmPLU&TNy8O9q$%HAO^WkEi6X1W zxrTzgfY{vFAh2)lfZiYeIvb|iS$X$mC4iA1X{gA!9`7Xiu(t04kW_K~g7_4`9H%<% zl&9dK!B5L%V}a1<PC!17bxPs~(&(@Bow-#|sKV%8fhU|J^OPzMY7VljsG&b4*i6lE ztd05Y(nTC@pN9m*|M*Dmx|HnR6BufGID0!Wa{c7}&Sxy_9HM`T3f<jQP&IUCQ4)(U zoKYd=((4PLO3JdJ_915_ex+lCS+;v097vxPrXcT&i#YmK*5|}i3FvjJQ$LzV4s~Ge znYX&~SlpAGr%9<a(~UF0Cv^`CZ`Yk7ZKxNvtFm3$;-lHrrA7NLdWE!4De5LCD`#N} z9o!j<oDq1W_dD(aO$AXF&GFmh&6<VspeeA8Q4lVeD18^_?_0Fqk?yXQQB3kTCYe|p z$wKP1i0SXFx{S#?$$yDd{gd)VvoP|pa^wv;idI2kXDog0E=v^ISo0j1yxu?J41N)= zKwMbZYDc1oxx}i#o6YQuWo6n$J8E5^o=AW^h>SHN`K2HZkzm~|+PN~a0JC=xx0!`y zSxl{<5!#?%%sQykBFUMjU1ABrNzPpA5!EC^q=#LboDUskS$epJ8i*rxq?7~<N-tCc zcG==@0po4?ZU#8_2d%r}6&6oC3gpnRi4-6!O7jvX)A0ct>9)25*hxbI7as)O`(0Fv zaM+i*zS3EIZ(*Nvj@5qhjMAaWX83b=qc@6IXdLo3>88LUe@ws)vZ_C0D~ajsbSW7@ z@lL3o<~P4!KrmcKE+FzCUo3yUE0XsGP^Cz&5S=ZA((a8CKqY~BgRTxI?q%yE$9Whq zULaJ)oJOB;V2}=cBDJN8lcErk$N?i$Qr#l!%VjNIBZ_<xxi^_sS21IqLv!!^?EWax zKRf9c@pL&udZ`GkR7UR;`@t`(n7I##)ayBMJaW<yU($8mr#NzqVSyy>L~u<Lg94u> z1sw_yo=k9Wpi1HE8W%bFRv?{faBFlM1$)nQpt2i3sX-|Kc&a<vf6DYbZ6~wHDbo22 za%N0^KU%|(UGJtFh-&P3p2~4j;5jTdB_t$}29rd`#hp*6@x6Tc5?xMDkNN;H{l(J3 zA$oj#JoG*+ENpLo-(qJZ2hCxwHst>H%5AehA+%#B+l@#8*W+Y)=}*fO92|p2Cx)P) zAaw}jrG&)b@ltEV#>Il?QVZN24$pW{j-`L|_;7FSbGbi75vAm25;dMFY_DHqf$i(- z8yypKy213AZun)|56Mg?SEPi<GDQvtB@MOe+%}9rYMfN*w!0J}H_BAj#CV<bRa$}h z*2iK*k>!(`tZidN-A}J^?aUI?mnaix%;k&5SR>?B_LBsM;vfQ^R*}~=oL15S94zGk zP!K5rS`f1jd142R0fdAtpCg<E1PhiUp`6gQ3~+ax6O(5JCkBJqNf1GmU_5Qo^(N*_ z5@%31EM6I4@wzC@fI=tLQ`5k-q_!={)swVHRdSk1Eo_hCBQB0=Fea~)Nv2vMdf&I^ zRThRYHe&T6cN6lg)l3OCkv7X7aUlu7M5xyy&cj<pNz)1NKUtMSIrAy-u)jGi4NiYC zDxZ3HI9r3s$@cs?;yG$+5pdPEBYn8oob;l)EwTFJ)(d(G_wa+N))D`xX`aT#?(N~M zxfb|~E!T|FJikn%_w6a~{m!!pcka&8I)^SUgb=@R5MviD)7569dG~X9E`5}GUwv;q ze*E~cdvankoGC1IJ|wv4J_$klcw}#8IrUkWUg`shzi!2A7sO^ism!06xEjwBQ<<yg z(ecU2o*2>Prm|Zt-n8c1<JP%48)6rFx6?lAI)^!dhre-;>A<{?t}vwc`96rb&#{g- z5}oWas`2IKC!6asl4#f0!E@7&pYyy%;trZ{@wuQAmEx}e$%^Y@94bk1tXS3&_Y|u9 z{;U*VY4l0S3K1amsCsxeyF;(r`7h*78Dxl5V~Bk8SA@+z;M_$b{=h&JJHAGS$zLc4 zp%Xqq64@LRSVj*!<ksBf);#1K8#gNaRIO5Dta3$)A-xCgJm{HseDef;RK%PUAB+Ej zNQGtwbhG;A3`U>+GB(mhuF^;0TPM+ql`;AI1Yt~;7{o!=W*684uD|%lS{HQ<jqvBx z+Wk<#b?UtLsA@Y?l{t;j_#MP__uc+vZ?C{qL$CdCch}s*gNl<4aZ`#IG<(=G^Y(p_ zf;TxiSwg@sES%!AtXkY%pcs~EI&-~~H@f7xGHe+q{X=-hc%zwL0XH->bjYJde{<RA zWDDQyFCtL<k7(yL<X;X>sS&5t$*OGsG_$x!-+8~#x#XOi<<!E7HW*m!N4TR9xnj*g zu~%OXQ`9>sJe$8v<WdL=v{I0u-#ZdBiHG2Vl9`KL4O!!Bmie?;XtB8j<bi{U0QM7* zS#A6`^+eN8W6zC1nbZZZ+(-x97ruw-j3B@*JOT^f%p}C9@UZcMa+1?@4~6Vlri3%` z1+KKyv#gZC2@z_zJ5yurp%4uCU!Yb{^Vnq*3!RO*hJ);)UZJ_BIEOzZ5E~c<+KFl6 zFZ@XrzF0IP^z`+7kv@_ECT-Zt4wZy5bW6y;>JonHO}?LuKG?c)@3ee9;_2E$h!Fj~ z9>ph8-^vSaHnx8EF7h9{M-dO_AFo<hw#rL$1&$aP7zq6Z#KklIAv;kI!R<18yfi!i z#B?8S<kZ|p@XAn2bt4rG1)R0D_0XTgLvGpoJq=n$Mv)_AEQ7t+sItr%DG{SoKPIu% z>eS;n(><w%^ra4F@UH{72jXbHZ-1)7ty;1yV_qIlAK6<>O0D%#VI0$H-st4HLp#x$ zSX4W>e35LzuF^Wh(Bu_|W`qMYki<G)eMT9ES?)>$7zBe=ss+av-X%km-B`HeNy_uC zp)@KqHf;Bc3e7KXrqg|PnwUi{R^zjpJ*{y?B%iLiL>1%Nn2SWkBEUo68Owb>uVGDE z_lP}_xmZ1EqMttcdK^hO9Ij3jL0$`UidO$9CScC`MbUyG>7p>Jnf)eoyV~BOG30!7 zxYG<G8WcF9pHr(#>US=RND5=}6QhRKP7n?LW8MAL%BW-GlC>PxM;xV{V4<M+k&%&- zsvoI5Mq(#z=YQ`IJF+WiKrb$;D8~Hg=xFEbt+Z#~ZMXjwE5FAp#7af$#e^EF_}Dvj z3`#Da5>+*C({)^adEd}pl3!_+_1?YF<o>e<j;3cHcf*$i)(~QBOsKQ~tfH6QItu`% z_DTZZ<fn<rmpRfR!vXSumjYFa^v}s|Szq68(2yQD-Xh50x@H=;u(*P%n;CMDH0<&Z z+mIUTyM5iXd{b6-o|#`B5Y~O>ce7XeMb+Lnk-yY_J=X^AW5CGw=Ff#MKVu4`!_kEU z!k-sadEN|2Xj1R3zk?SHwlHd^mJny8X){%{=rg>49)yP&u!)pcj6u2YfK<Q__POb7 zM>!uUI1$3x*HM*weX~OSy9l!wXV!)8h#@<odNOzRgJf}zXQED<YGyZydNZiHnAUms zw$69O_sZp@{c2)-ybC2#w8j-b$*UEFEaGn%qTfdL)_@tV?><|S6Erb1GgI%_6G}KV zGIG|9&-dYy>EU-+^PhS9;Xh$A7cAS`+hsajh~%GdWiHD#VC6a=ei|)ze~ObCT)9V0 zL59({0&o~tOR}8S@6JbUZvPyieO$$4TJ6GN5(0nwnZ~!1>vR0Z+}vNQym#epc;)wH zHA4ETC1@Tj$&xMCkK?K+qmcF2n?x%`A{i4kjcQCeXU5ta^>BDpnH|#*=~UXu+TGMI zM;PN>CN114PzykwkJtH-ZKZSADD4ix3T{=Nkq<O+;o6<}yTFW*y_|TSKU;v^&rCv& zs@GOrptYDyUrmPCyzN6&cErFX(gWX~T5_|nj5|fRD#)diBpkHu0_looN_u4f7`8jd zHkS~riZpSK@J!^vYglp?BlGhGHA)FI5#ByN&#a4whK8IM92?P{XG}a%R}iLLgW+3L zk@Y`4b#ZDv5;<-;;O)3-KdEtC5E<M$3sjH_Q3zOGUM{)jyveLR9#ABf?)~Pt(6s-# zqUm}&D<dxtN2_uBdjRIYOVy&LpTTpntD?H&-JgT~{Xy(xl(VTr{nPSgl_#PGby1>B zjTcgKxeG`3ul(fBY>lPEQcFr~ED>+(p}@nY#zXM+wbya;PA-+Fa9OkQtnI{cLouda z=C85^q1~n;3q`V)%7ybD83Rq2jms+NGx|>lpw?D-(M%pY67Tk>WNjJ%P7h)m!Xtb3 z#I+7W7`=ONd2oMg-UtzJK`cu<n9Hrj^ov}9ni^-_$fQ)pnbGWIq9nho36~wX?Y2=& z9xH<Jh(ywQ6(aflEgxvPN!01O#cx&uTp`9Z15gH2TNPlMB1Se=JJ@{??d?j3FUswW zS5(X#NIl-2%iX;F(gR#tTKXZ6{^4R=`MMNw1N_H0m;1{ZZC*qgWMyOo>c2<=F*9R= zQMg>}jxXBJw|eqPOG^_F6T7W`N7t4``MllTG8g@enu;l|OYa;c6GH0hLwkEWqzAl$ zD&&86m1PHWJeLP<m#<`Ueg7Do&t0~UIsG$-v~+aq&zY`O(2{4qaEGH_-~##j9*)yI z%=-l*cS_0-RtA@oD{|oVKvi#&9D9p>`C*D~92!S$G3%hQye_!Mg|PDOxHfu}P;8{_ zR(_LjNYdZWvTn<*Zi>Op`WdvK;ic345XJ%%4wpsBlhML+C_VG(6W_f>`Xh(k1~5U9 zisZ09Cc$jTq%kh+O{>%lJHCcfmgeMe)^=w88#Wt6D)bwZIG!`v1^Wc&PkB@<9X;?F z6J&qCij$9xO=$qpjQse`kd2HY$}Nkoe5~8axBWU>`&O;zB_E0%Xr|tK#fxq-m%p^> zWj>~_T<5F|I9BU$ZD*<$lWn=q4G9fuYiPu!eOliy2xGMP@FAVY=$ms7p=kP7O~K2n zt44&B-k3!)gWN(xDHe0Ph%nb%(@gTB+_2BCI>8<mi6Dq2ghZ<Z)3wk|X9A~vR^oD% znlqth*od^Ha{vN^bESod1?aOLxXe?jokO`Ht$q<L-hFn*;1<H(qGk>WCbl1&5#iZs zj?^Uh)z#&qd?Zk&^GHV~+J%m?4K<)=FhXpYkL4SmK^l8Ch&>Phb$d18JGn@9F2#^y zl(?N$#;<X>lm5Yr-8+XubhNiJj<wzUYc{I!!;>SlZGP;vQmk3ad#gE?1uh+uzuwpD z98A$O9hm9(Bm7UYxnA3}uauSdj*qP;OCatZ9&{XgdwZw!6#g5?xN|+krQRaKYbOU) zAn8bEo85q;GPm4~i>~+$hA}9kOXrW0Y^H|aS(4QCW)cJ)RS;5TAJ1iX-ar0%U;esc z(dVT7aK0g`xmo<xt5;3GyYUHebt`oJOU5*L(;%^fpLHwLeNkC!^*ph*un1IU@=g9{ zE>Mp%`W(KT+?ltpev3rJG91p;g;iDYE<gNfJU8mRG+J~)G5}pGf?THt!7lR!Az6up zx3YO3zM!E!#rn5Qpl>G%di*@ydHCg1pn?1FP_(=l6hGaV@~8#(pir!w%g&_mr#Drs z`+P%IBC2AV1f)j)3|uLZEu=mhSQb3`Ep{a*_Go{Ebw$$crh!;&ORkJ!&K`@7jrH<k z$gK;6sKc{UdapkmcPNCp2#lyySq3i63=0~li<P3QFZv0I2v-x}Nu0w`Qg?ESUAb*v z*=RrU<(n}>NHabDMed!P?Cg$z`qydoKacxri6mmi#u05)JV;PxT<f?!-q^3GwsvqJ z@CShZF0I@nOl0oXh~3VIMeAI*RD($l7aHT<f82OxO6HWC`|%9Cj8e4gMvUm$o(5uG zObTVFEKio(Ki)2^Jkdg%YkY4u`7sp*-k+ld<n79%-}2+bm5-z7@`vZ2K7IOlV6?KH zly?U(yIZFQC-&BxId@_IYeTrrI_Nps_&V<d@(>RfrOhWDw^ScIgQ(b%oTPIwy#`FL zW=;<Z?Jb8{oV#rDBHB%3+XV1>uwVTV-;s`GSV9rrLb_%oCM#nlO+Pax_f0o<u!^MC z?U5LAVuIOXn?SOF;e=83WSEW4(~+XCBsx>;3wk%vg$L({wW(X?0Cm|ge735jHH@&% zY6KvGO5mbKcyn{60`r~Rl;enxr5N&6ht%8m+ON^o1D7`q$<&r`uz3g@Ty@UomtaV^ z5oklwL!I2Tb!<D*1rj`IZGE!ZXoOqi*kK<ChZbFYgIiR(K)*WDy)KeWc@^)C#aJ}n zw8T8umZg^p%FRlYj&Yt2PMW?SyKUk-L?CV5Rk<nV9%3y69V$KJibvneP1=oKf6RP| znT{GLr9(4<$SCSBHe<Pl=j)vCKIE@M!5&+)xAQ6dv#du14Do;TS^_BHwv;Pl3BYG; zE;*F9iGb8MLizc(lHb<?!^cLHs1yX=zF+Y3OISgdj9h?BDt-pf8>ql^%(JPm5ZgVH zW2@qPT3bJ?v&jgVa)Syr3YN$cM4#i>^eoQ)h)XUPjGE+m0>wa`#tSvwqDW3*jCK|8 ztGSZago%VZFDwM87OsMb{q|ak){55h>JKy7_Sm>edr+GJ#!U;y+)NB3FTZ2_UCZu` zF;4gPSvn5;$~2Voawjx6xL;fo5kzXK>_A95*8q!to|sFpM*q`|PfAb8+bN<oE`ZF< zJ0x;$>wI|UtgBb8d>|lYH4_C2J!(w^Z*WRsk>cy~Mn-T5oY^oS(#@7HV|oBXxPWm3 ztq56L&N=Tg{<V;}a`_^^x(c;W&`Wq;Hqt#OO01<`#^J-%Cb4#$NIQ%W#QC)~<j*&L zmlQzyeKT!WTT%`qU097^U$}|IZ^B-%u~)vYF9>YfsSZCF%+F`WMM3b(kY|ZPE(p^~ z?mO+5Gr7L&l%>_^Rp768I7%n)5wopd3pL&bbYW7tc{>VQjpUpkx4d-HW{ekNvJ({L z{rOJf5#WOhAFYijUG_zw+mH%NnUl6e9Te_b8PBktE*F2xahUBF$I9?E42)=%g;1;l zILeAqb2;n=-D#cyI~>EE(s~@q_PsDkXJg78GOS(T?|Fu2giJG+@l})0kD5c`xA!`l zS#liYH)ASeL|=Wlk~h;VNpepOIzJA==kX{?<E3pPigcRMOhiY})#-qrsJ7iv1slYO zP@4}4ms#TQKgIJ_L~VR=*mfDBl?l~L0@k<6%oW55$wtr!Ge}5?%*84iKX)zUSgo6t zNXH391)4wSt|GO_2d8W5QU%k=Tm{<Kn6JSvl;IH$A23`M$#`OTBU;|o<zN%G=CtVG z<83tEPB5z1wthoY5#ZsyD?v@?<fBrH?pfcDp>g^B`oTn))rI$9cgW{QpB@jT!5w8# z;p^!R$)~l%1$gk}I_xVyko|Eo+Gx1J>6hRXM^2<=m|!dik<wLtda2RpB?zB5iTX`E ziKSkPC?v;7N+pz+M;QxLM7zPiMj$S?fA7y`g5BsNvk@tF!d^}0>phY6Z<w##M@|X8 zrso{C4zzuJSwcWt+-`NO^1@B^deHYl-CCI#REq;&O8ZuYsvm_AvrdO4G93DUGQC&- zht@9KjwQb~-Y-+aotE!cqUeNyJ}EoFra)+8)-w^;Zgo0WSB>Y3g_w$jGb?97x2m<2 zUvLnQ#`$2nThzFXteJ*m;G)h6O!Ni|m4KTJ4m4HN`s28Td`NUkV#ABY00WWlp*e*~ z-)uC>)84&DqcRamo5$rLM6yiQGc(!=DEJi6I@o^Bs7R!)8YtJ-+-0xJkuGuW(Fd-l z);pqLHjMs9q8uF_3Z4Gz0Vffix;hU;gwIgu_`Iy|a=D55OPl^6syhi$gBkqCdfhBy zzN6NmiqS81^%jiZ(;GFCj;zPdT9y*O#h}mx7XHiG`|!mCPtvdJy_$;|ybtT|W83)S zTOIj&+*FM@(1qLeZ`SB%$_G9crM~MoFv!m&jl4Js*x};g*O{!0Yn(rbXhE>y?~_na zxEKB_Ef=8`2KvCxinJgLkDuL<3ucs=JJTX5V~<(r)ZeRO6fBLLE-hZ2hmNUkhXXgi z)>q+cq84<#IsXAQss-th@bb;6t>Xyq%o5z^C4;(-?kKqjucW&1L}@<|<UT=unp(?h zXuwQtlYuxb6pk`bP+TBF|AV<)3#wo0WmdX4{mu5}*|)&d5DZA{LT$b;^z{n+kz)X8 ziYHPKBN>IBz`xofF*QhdP|xfyRa*464`ZD=3T^}iMM?W*J>a7!vfHn;SDin>#=dv> z$2eO~&MfVT{OrM!W7R0t09kK7c61Mx`vp7FTc4<6gs}LlI$DYMy_Z=3|ATU_8BROl zL=l5xVPZq8x+ipN#Y=V?ftd=pdksR;zG#W4-sv^ECThA%-2hk3B>XK7|Dpi?vicTg zD2CndQInp8PJyn9`ufFxXJwcYA%0tMy8}TO+-+r3<f!}O@}ppzfAJ4C{fzvOP!H&Z zzM4tthA<8`c7qP;<!!#8E|A<XH4-Bn3%lL!Kiv!$^^Hu6Q{s`3QBZ*XJ;JPqP81jz cm>T{d>-Lb=7PY@6gogTnm7t(11@plF0R^pZAOHXW From c03b702131ad8e467e6031050fe0927b90f03faa Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Wed, 17 May 2017 22:15:16 +0200 Subject: [PATCH 18/32] Speedup for microcontrast, fixes #3867 --- rtengine/ipsharpen.cc | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index cb98fe907..a730b9496 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -23,17 +23,15 @@ #include "rt_math.h" #include "sleef.c" #include "opthelper.h" + using namespace std; -#define BENCHMARK -#include "StopWatch.h" + namespace rtengine { #undef ABS #define ABS(a) ((a)<0?-(a):(a)) -#define CLIREF(x) LIM(x,-200000.0f,200000.0f) // avoid overflow : do not act directly on image[] or pix[] - extern const Settings* settings; SSEFUNCTION void ImProcFunctions::dcdamping (float** aI, float** aO, float damping, int W, int H) @@ -569,13 +567,12 @@ void ImProcFunctions::MLmicrocontrast(float** luminance, int W, int H) if (!params->sharpenMicro.enabled) { return; } -BENCHFUN const int k = params->sharpenMicro.matrix ? 1 : 2; // k=2 matrix 5x5 k=1 matrix 3x3 const int width = W, height = H; - const float uniform = params->sharpenMicro.uniformity;//between 0 to 100 + const float uniform = params->sharpenMicro.uniformity; //between 0 to 100 const int unif = (int)(uniform / 10.0f); //put unif between 0 to 10 float amount = params->sharpenMicro.amount / 1500.0f; //amount 2000.0 quasi no artefacts ==> 1500 = maximum, after artefacts @@ -629,7 +626,7 @@ BENCHFUN for(int j = 0; j < height; j++) for(int i = 0, offset = j * width + i; i < width; i++, offset++) { - LM[offset] = luminance[j][i] / 327.68f; // adjust to 0.100 and to RT variables + LM[offset] = luminance[j][i] / 327.68f; // adjust to [0;100] and to RT variables } #ifdef _OPENMP @@ -663,7 +660,7 @@ BENCHFUN LM[offset - 2 * width - 1] + LM[offset - 2 * width + 1] + LM[offset - width + 2] + LM[offset - width - 2]); temp2 -= sqrt2 * (LM[offset + 2 * width - 2] + LM[offset + 2 * width + 2] + LM[offset - 2 * width - 2] + LM[offset - 2 * width + 2]); - temp2 += 18.601126159f * v ; + temp2 += 18.601126159f * v ; // 18.601126159 = 4 + 4 * sqrt(2) + 8 * sqrt(1.25) temp2 *= 2.f * s; temp += temp2; } From e242afedd67bb826f1b40ae40c50ca947c8b4e57 Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Wed, 24 May 2017 14:46:19 +0200 Subject: [PATCH 19/32] On Windows, previously opened raw files can't be moved or deleted until RawTherapee is closed. Fixes #3884 --- rtengine/rawimage.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index d8dc7eb1d..7b6ee8782 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -39,6 +39,7 @@ RawImage::~RawImage() { if(ifp) { fclose(ifp); + ifp = nullptr; } if( image ) { @@ -410,7 +411,11 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro verbose = settings->verbose; oprof = nullptr; - ifp = gfopen (ifname); // Maps to either file map or direct fopen + if(!ifp) { + ifp = gfopen (ifname); // Maps to either file map or direct fopen + } else { + fseek (ifp, 0, SEEK_SET); + } if (!ifp) { return 3; From 408fc858e1b5104e614cadfaa599b1474add0593 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood <bugs@londonlight.org> Date: Thu, 25 May 2017 12:02:11 +0200 Subject: [PATCH 20/32] Support opening filenames with spaces in external editor in Windows, fixes #3883 --- rtgui/extprog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index bdbbb85b4..33424fac9 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -324,7 +324,7 @@ bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName) #if defined WIN32 const auto cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\""); - auto success = ShellExecute( NULL, "open", cmdLine.c_str(), fileName.c_str(), NULL, SW_SHOWNORMAL ); + auto success = ShellExecute( NULL, "open", cmdLine.c_str(), ('"' + fileName + '"').c_str(), NULL, SW_SHOWNORMAL ); return (uintptr_t)success > 32; #elif defined __APPLE__ From 136c9153e65fe5071739120d29ff7025a52b106e Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Fri, 26 May 2017 21:06:37 +0200 Subject: [PATCH 21/32] Improved accuracy of Pixel Shift motion mask, no Issue --- rtengine/pixelshift.cc | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 835aa7631..5c05c2a1d 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -50,15 +50,7 @@ float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperI avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); - float result = gDiff - stddev; - - if(!showMotion) { - return result; - } else if(result > 0.f) { // for the motion mask - return std::fabs(a - b) / (std::max(a, b) + 0.01f); - } else { - return 0.f; - } + return std::max(gDiff - stddev, 0.f); #ifdef PIXELSHIFTDEV } else { @@ -110,14 +102,7 @@ float nonGreenDiffCross(float right, float left, float top, float bottom, float prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); float result = std::min(hDiff, vDiff) - stddev; - - if(!showMotion) { - return result; - } else if(result > 0.f) { // for the motion mask - return std::sqrt((result / (stddev + result + 0.01f))); - } else { - return 0.f; - } + return std::max(std::min(hDiff, vDiff) - stddev, 0.f); } void paintMotionMask(int index, bool showMotion, float gridMax, bool showOnlyMask, float *maskDest, float *nonMaskDest0, float *nonMaskDest1) From fd295356575d087512a094b536cb1bc14f6fcb02 Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Sat, 27 May 2017 11:51:13 +0200 Subject: [PATCH 22/32] pixelshif.cc compilation warning. fixes #3889 --- rtengine/pixelshift.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 5c05c2a1d..a27ea71c8 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -101,7 +101,6 @@ float nonGreenDiffCross(float right, float left, float top, float bottom, float avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); - float result = std::min(hDiff, vDiff) - stddev; return std::max(std::min(hDiff, vDiff) - stddev, 0.f); } From 58b3ed7c4397f742283c37400a9284cfb0b10ddc Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Sat, 27 May 2017 14:12:48 +0200 Subject: [PATCH 23/32] rawtherapee-cli (5.1) crashing with -t option. Fixes #3891 --- rtgui/main-cli.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index 2d5efddb1..2a2afca63 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -425,7 +425,7 @@ int processLineParams( int argc, char **argv ) case 't': outputType = "tif"; - compression = ((currParam.at(2) != 'z') ? 0 : 1); + compression = ((currParam.size() < 3 || currParam.at(2) != 'z') ? 0 : 1); break; case 'n': From 25a531308fbec3cb3fd01ccdd143621dc3c248c4 Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Tue, 30 May 2017 15:43:49 +0200 Subject: [PATCH 24/32] Cleaned pixelshift code and made a speedup for pixelshift without motion correction --- rtengine/pixelshift.cc | 1026 +++++++++------------------------------- 1 file changed, 233 insertions(+), 793 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index a27ea71c8..71212b0b3 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -1,13 +1,8 @@ //////////////////////////////////////////////////////////////// // -// pentax pixelshift algorithm with motion detection +// Algorithm for Pentax Pixel Shift raw files with motion detection // -// -// If motion correction is enabled only the pixels which are not detected as motion are set -// That means for a complete image you have to demosaic one of the frames with a bayer demosaicer to fill red, green and blue -// before calling pixelshift in case motion correction is enabled. -// -// copyright (c) Ingo Weyrich 2016 +// Copyright (C) 2016 - 2017 Ingo Weyrich <heckflosse67@gmx.de> // // // pixelshift.cc is free software: you can redistribute it and/or modify @@ -31,65 +26,29 @@ #include "procparams.h" #include "gauss.h" #include "median.h" -#define BENCHMARK -#include "StopWatch.h" namespace { -float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +float greenDiff(float a, float b, float stddevFactor, float eperIso, float nreadIso, float prnu) { // calculate the difference between two green samples -#ifdef PIXELSHIFTDEV - if(adaptive) { -#endif - float gDiff = a - b; - gDiff *= eperIso; - gDiff *= gDiff; - float avg = (a + b) * 0.5f; - avg *= eperIso; - prnu *= avg; - float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); - return std::max(gDiff - stddev, 0.f); -#ifdef PIXELSHIFTDEV - - } else { - float gDiff = std::fabs(a - b); - // add a small epsilon to avoid division by zero - float maxVal = std::max(a, b) + 0.01f; - return gDiff / maxVal; - } -#endif -} - -#ifdef PIXELSHIFTDEV -float nonGreenDiff(float a, float b, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) -{ - // calculate the difference between two nongreen samples float gDiff = a - b; gDiff *= eperIso; gDiff *= gDiff; - float avg = (a + b) / 2.f; + float avg = (a + b) * 0.5f; avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); - float result = gDiff - stddev; - - if(!showMotion) { - return result; - } else if(result > 0.f) { // for the motion mask - return std::fabs(a - b) / (std::max(a, b) + 0.01f); - } else { - return 0.f; - } + return gDiff - stddev; } -#endif -float nonGreenDiffCross(float right, float left, float top, float bottom, float centre, float clippedVal, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +float nonGreenDiffCross(float right, float left, float top, float bottom, float centre, float clippedVal, float stddevFactor, float eperIso, float nreadIso, float prnu) { if(rtengine::max(right, left, top, bottom, centre) > clippedVal) { return 0.f; } + // check non green cross float hDiff = (right + left) * 0.5f - centre; hDiff *= eperIso; @@ -101,28 +60,32 @@ float nonGreenDiffCross(float right, float left, float top, float bottom, float avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); - return std::max(std::min(hDiff, vDiff) - stddev, 0.f); + return std::min(hDiff, vDiff) - stddev; } -void paintMotionMask(int index, bool showMotion, float gridMax, bool showOnlyMask, float *maskDest, float *nonMaskDest0, float *nonMaskDest1) +void paintMotionMask(int index, bool showMotion, bool showOnlyMask, float *maskDest, float *nonMaskDest0, float *nonMaskDest1) { if(showMotion) { if(!showOnlyMask) { // if showMotion is enabled colourize the pixel - maskDest[index] = 1000.f + 25000.f * gridMax; + maskDest[index] = 13500.f; nonMaskDest1[index] = nonMaskDest0[index] = 0.f; } else { - maskDest[index] = nonMaskDest0[index] = nonMaskDest1[index] = 1000.f + 25000.f * gridMax; + maskDest[index] = nonMaskDest0[index] = nonMaskDest1[index] = 65535.f; } } } void invertMask(int xStart, int xEnd, int yStart, int yEnd, const array2D<uint8_t> &maskIn, array2D<uint8_t> &maskOut) { +#ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) +#endif for(int i = yStart; i < yEnd; ++i) { +#ifdef _OPENMP #pragma omp simd +#endif for(int j = xStart; j < xEnd; ++j) { maskOut[i][j] = ~maskIn[i][j]; @@ -132,10 +95,14 @@ void invertMask(int xStart, int xEnd, int yStart, int yEnd, const array2D<uint8_ void xorMasks(int xStart, int xEnd, int yStart, int yEnd, const array2D<uint8_t> &maskIn, array2D<uint8_t> &maskOut) { +#ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) +#endif for(int i = yStart; i < yEnd; ++i) { +#ifdef _OPENMP #pragma omp simd +#endif for(int j = xStart; j < xEnd; ++j) { maskOut[i][j] ^= maskIn[i][j]; @@ -152,7 +119,7 @@ void floodFill4Impl(int y, int x, int xStart, int xEnd, int yStart, int yEnd, ar coordStack.pop(); auto x = coord.first, y = coord.second; - if (mask[y][x] == 255) { + if(mask[y][x] == 255) { auto yUp = y - 1, yDown = y + 1; bool lastXUp = false, lastXDown = false, firstXUp = false, firstXDown = false; mask[y][x] = 0; @@ -228,27 +195,37 @@ void floodFill4Impl(int y, int x, int xStart, int xEnd, int yStart, int yEnd, ar void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D<uint8_t> &mask) { +#ifdef _OPENMP #pragma omp parallel +#endif { std::stack<std::pair<uint16_t, uint16_t>, std::vector<std::pair<uint16_t, uint16_t>>> coordStack; +#ifdef _OPENMP #pragma omp for schedule(dynamic,128) nowait +#endif for(uint16_t i = yStart; i < yEnd; i++) { floodFill4Impl(i, xStart, xStart, xEnd, yStart, yEnd, mask, coordStack); } +#ifdef _OPENMP #pragma omp for schedule(dynamic,128) nowait +#endif for(int16_t i = yEnd - 1; i >= 0 ; i--) { floodFill4Impl(i, xEnd - 1, xStart, xEnd, yStart, yEnd, mask, coordStack); } +#ifdef _OPENMP #pragma omp sections nowait +#endif { +#ifdef _OPENMP #pragma omp section +#endif { uint16_t i = yStart; @@ -257,7 +234,9 @@ void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D<uint8_t> &ma floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); } } +#ifdef _OPENMP #pragma omp section +#endif { uint16_t i = yStart; @@ -266,7 +245,9 @@ void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D<uint8_t> &ma floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); } } +#ifdef _OPENMP #pragma omp section +#endif { uint16_t i = yEnd; @@ -275,7 +256,9 @@ void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D<uint8_t> &ma floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); } } +#ifdef _OPENMP #pragma omp section +#endif { uint16_t i = yEnd; @@ -291,11 +274,12 @@ void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D<uint8_t> &ma void calcFrameBrightnessFactor(unsigned int frame, uint32_t datalen, LUT<uint32_t> *histo[4], float brightnessFactor[4]) { float medians[4]; + for(int i = 0; i < 4; ++i) { //find median of histogram uint32_t median = 0, count = 0; - while (count < datalen / 2) { + while(count < datalen / 2) { count += (*histo[i])[median]; ++median; } @@ -317,20 +301,15 @@ using namespace std; using namespace rtengine; void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RAWParams::BayerSensor &bayerParamsIn, unsigned int frame, const std::string &model, float rawWpCorrection) { -#ifdef PIXELSHIFTDEV - BENCHFUN -#endif if(numFrames != 4) { // fallback for non pixelshift files - amaze_demosaic_RT (0, 0, winw, winh, rawData, red, green, blue); + amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue); return; } RAWParams::BayerSensor bayerParams = bayerParamsIn; -#ifndef PIXELSHIFTDEV bayerParams.pixelShiftAutomatic = true; -#endif if(bayerParams.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Automatic) { bool pixelShiftEqualBright = bayerParams.pixelShiftEqualBright; @@ -344,159 +323,71 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA if((bayerParams.pixelShiftMotion > 0 || bayerParams.pixelShiftAutomatic)) { if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction -#ifdef PIXELSHIFTDEV - if(!bayerParams.pixelShiftMedian3) { -#endif - if(bayerParams.pixelShiftLmmse) { - lmmse_interpolate_omp(winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.lmmse_iterations); - } else { - amaze_demosaic_RT (0, 0, winw, winh, *(rawDataFrames[0]), red, green, blue); - } - multi_array2D<float,3> redTmp(W,H); - multi_array2D<float,3> greenTmp(W,H); - multi_array2D<float,3> blueTmp(W,H); - for(int i=0;i<3;i++) { - if(bayerParams.pixelShiftLmmse) { - lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i+1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.lmmse_iterations); - } else { - amaze_demosaic_RT (0, 0, winw, winh, *(rawDataFrames[i+1]), redTmp[i], greenTmp[i], blueTmp[i]); - } - } - #pragma omp parallel for schedule(dynamic,16) - for(int i=border;i<H-border;i++) { - for(int j=border;j<W-border;j++) { - red[i][j] = median(red[i][j],redTmp[0][i+1][j],redTmp[1][i+1][j+1],redTmp[2][i][j+1]); - } - for(int j=border;j<W-border;j++) { - green[i][j] = median(green[i][j],greenTmp[0][i+1][j],greenTmp[1][i+1][j+1],greenTmp[2][i][j+1]); - } - for(int j=border;j<W-border;j++) { - blue[i][j] = median(blue[i][j],blueTmp[0][i+1][j],blueTmp[1][i+1][j+1],blueTmp[2][i][j+1]); - } - } -#ifdef PIXELSHIFTDEV + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.lmmse_iterations); } else { - multi_array2D<float,3> redTmp(W,H); - multi_array2D<float,3> greenTmp(W,H); - multi_array2D<float,3> blueTmp(W,H); - for(unsigned int i=0, frameIndex = 0;i<4;++i) { - if(i != currFrame) { - if(bayerParams.pixelShiftLmmse) { - lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i]), redTmp[frameIndex], greenTmp[frameIndex], blueTmp[frameIndex], bayerParams.lmmse_iterations); - } else { - amaze_demosaic_RT (0, 0, winw, winh, *(rawDataFrames[i]), redTmp[frameIndex], greenTmp[frameIndex], blueTmp[frameIndex]); - } - ++frameIndex; - } - } - unsigned int offsX0 = 0, offsY0 = 0; - unsigned int offsX1 = 0, offsY1 = 0; - unsigned int offsX2 = 0, offsY2 = 0; + amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[0]), red, green, blue); + } - // We have to adjust the offsets for the selected subframe we exclude from median - switch (currFrame) { - case 0: - offsY0 = 1; - offsX0 = 0; - offsY1 = 1; - offsX1 = 1; - offsY2 = 0; - offsX2 = 1; - break; + multi_array2D<float, 3> redTmp(winw, winh); + multi_array2D<float, 3> greenTmp(winw, winh); + multi_array2D<float, 3> blueTmp(winw, winh); - case 1: - offsY0 = 0; - offsX0 = 0; - offsY1 = 1; - offsX1 = 1; - offsY2 = 0; - offsX2 = 1; - break; - - case 2: - offsY0 = 0; - offsX0 = 0; - offsY1 = 1; - offsX1 = 0; - offsY2 = 0; - offsX2 = 1; - break; - - case 3: - offsY0 = 0; - offsX0 = 0; - offsY1 = 1; - offsX1 = 0; - offsY2 = 1; - offsX2 = 1; - } - - #pragma omp parallel for schedule(dynamic,16) - for(int i=border;i<H-border;i++) { - for(int j=border;j<W-border;j++) { - red[i][j] = median(redTmp[0][i+offsY0][j+offsX0],redTmp[1][i+offsY1][j+offsX1],redTmp[2][i+offsY2][j+offsX2]); - } - for(int j=border;j<W-border;j++) { - green[i][j] = median(greenTmp[0][i+offsY0][j+offsX0],greenTmp[1][i+offsY1][j+offsX1],greenTmp[2][i+offsY2][j+offsX2]); - } - for(int j=border;j<W-border;j++) { - blue[i][j] = median(blueTmp[0][i+offsY0][j+offsX0],blueTmp[1][i+offsY1][j+offsX1],blueTmp[2][i+offsY2][j+offsX2]); - } + for(int i = 0; i < 3; i++) { + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.lmmse_iterations); + } else { + amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i]); } } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) #endif + + for(int i = winy + border; i < winh - border; i++) { + for(int j = winx + border; j < winw - border; j++) { + red[i][j] = median(red[i][j], redTmp[0][i + 1][j], redTmp[1][i + 1][j + 1], redTmp[2][i][j + 1]); + } + + for(int j = winx + border; j < winw - border; j++) { + green[i][j] = median(green[i][j], greenTmp[0][i + 1][j], greenTmp[1][i + 1][j + 1], greenTmp[2][i][j + 1]); + } + + for(int j = winx + border; j < winw - border; j++) { + blue[i][j] = median(blue[i][j], blueTmp[0][i + 1][j], blueTmp[1][i + 1][j + 1], blueTmp[2][i][j + 1]); + } + } } else { if(bayerParams.pixelShiftLmmse) { lmmse_interpolate_omp(winw, winh, rawData, red, green, blue, bayerParams.lmmse_iterations); } else { - amaze_demosaic_RT (0, 0, winw, winh, rawData, red, green, blue); + amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue); } } } else if(bayerParams.pixelShiftMotionCorrectionMethod != RAWParams::BayerSensor::Off) { if(bayerParams.pixelShiftLmmse) { lmmse_interpolate_omp(winw, winh, rawData, red, green, blue, bayerParams.lmmse_iterations); } else { - amaze_demosaic_RT (0, 0, winw, winh, rawData, red, green, blue); + amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue); } } - const int motion = bayerParams.pixelShiftMotion; const bool showMotion = bayerParams.pixelShiftShowMotion; const bool showOnlyMask = bayerParams.pixelShiftShowMotionMaskOnly && showMotion; const bool adaptive = bayerParams.pixelShiftAutomatic; -#ifdef PIXELSHIFTDEV - const RAWParams::BayerSensor::ePSMotionCorrection gridSize_ = bayerParams.pixelShiftMotionCorrection; - const bool detectMotion = bayerParams.pixelShiftMotion > 0; - float stddevFactorGreen = bayerParams.pixelShiftStddevFactorGreen; - float stddevFactorRed = bayerParams.pixelShiftStddevFactorRed; - float stddevFactorBlue = bayerParams.pixelShiftStddevFactorBlue; - float nreadIso = bayerParams.pixelShiftNreadIso; - float prnu = bayerParams.pixelShiftPrnu; - const float redBlueWeight = bayerParams.pixelShiftRedBlueWeight + 1.f; -#else - float stddevFactorGreen = 5.f; - float stddevFactorRed = 5.f; - float stddevFactorBlue = 5.f; - float nreadIso = 0.f; - float prnu = 1.f; - const float redBlueWeight = 0.7f + 1.f; -#endif + constexpr float stddevFactorGreen = 25.f; + constexpr float stddevFactorRed = 25.f; + constexpr float stddevFactorBlue = 25.f; + constexpr float prnu = 0.01f; + constexpr float redBlueWeight = 0.7f + 1.f; float eperIso = bayerParams.pixelShiftEperIso; const bool checkNonGreenCross = bayerParams.pixelShiftNonGreenCross; const bool checkGreen = bayerParams.pixelShiftGreen; - const float greenWeight = 2.f; + constexpr float greenWeight = 2.f; const bool blurMap = bayerParams.pixelShiftBlur; const float sigma = bayerParams.pixelShiftSigma; -#ifdef PIXELSHIFTDEV - const bool checkNonGreenHorizontal = bayerParams.pixelShiftNonGreenHorizontal; - const bool checkNonGreenVertical = bayerParams.pixelShiftNonGreenVertical; - const bool checkNonGreenAmaze = bayerParams.pixelShiftNonGreenAmaze; - const bool checkNonGreenCross2 = bayerParams.pixelShiftNonGreenCross2; - const float threshold = bayerParams.pixelShiftSum + 9.f; - const bool experimental0 = bayerParams.pixelShiftExp0; -#else constexpr float threshold = 3.f + 9.f; -#endif const bool holeFill = bayerParams.pixelShiftHoleFill; const bool equalBrightness = bayerParams.pixelShiftEqualBright; const bool equalChannel = bayerParams.pixelShiftEqualBrightChannel; @@ -530,8 +421,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 1.5f, // ISO 25600 1.5f, // ISO 32000 1.5f, // ISO 40000 - 1.5f, // ISO 51200 - 1.5f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + 1.5f // ISO 51200 }; static const float ePerIsoK3II = 0.35f; @@ -574,6 +464,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA static const float ePerIsoK1 = 0.75f; + // currently nReadK70 is used for K-70 and KP static const float nReadK70[] = { 4.0f, // ISO 100 4.0f, // ISO 125 4.0f, // ISO 160 @@ -602,50 +493,28 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 3.0f, // ISO 32000 3.0f, // ISO 40000 3.0f, // ISO 51200 - 3.0f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + 3.0f, // ISO 64000 + 3.0f, // ISO 80000 + 3.0f, // ISO 102400 + 3.0f, // ISO 128000 + 3.0f, // ISO 160000 + 3.0f, // ISO 204800 + 3.0f, // ISO 256000 + 3.0f, // ISO 320000 + 3.0f, // ISO 409600 + 3.0f, // ISO 512000 + 3.0f, // ISO 640000 + 3.0f // ISO 819200 }; static const float ePerIsoK70 = 0.5f; - if (plistener) { - plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift])); + if(plistener) { + plistener->setProgressStr(Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift])); plistener->setProgress(0.0); } - -#ifdef PIXELSHIFTDEV - const bool skip = (gridSize_ == RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2); - int gridSize = 1; - - bool nOf3x3 = false; - - switch (gridSize_) { - case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x1: - case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2: - gridSize = 1; - break; - - case RAWParams::BayerSensor::ePSMotionCorrection::Grid3x3: - gridSize = 3; - break; - - case RAWParams::BayerSensor::ePSMotionCorrection::Grid5x5: - gridSize = 5; - break; - - case RAWParams::BayerSensor::ePSMotionCorrection::Grid7x7: - gridSize = 7; - break; - - case RAWParams::BayerSensor::ePSMotionCorrection::Grid3x3New: - gridSize = 1; - nOf3x3 = true; - } -#else - const bool nOf3x3 = true; -#endif - - if(adaptive && blurMap && nOf3x3 && smoothFactor == 0.f && !showMotion) { + if(adaptive && blurMap && smoothFactor == 0.f && !showMotion) { if(plistener) { plistener->setProgress(1.0); } @@ -653,20 +522,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA return; } -#ifdef PIXELSHIFTDEV - // Lookup table for non adaptive (slider) mode - LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); - - if(detectMotion && !adaptive) { - const float lutStrength = 2.f; - log2Lut[0] = 0; - - for(int i = 2; i < 65536; i += 2) { - log2Lut[i >> 1] = lutStrength * log2(i) / 100.f; - } - } -#endif - const float scaleGreen = 1.f / scale_mul[1]; float nRead; @@ -680,27 +535,15 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } else if(model.find("K-1") != string::npos) { nRead = nReadK1[nReadIndex]; eperIsoModel = ePerIsoK1; - } else { + } else { // as long as we don't have values for Pentax KP, we use the values from K-70 nRead = nReadK70[nReadIndex]; eperIsoModel = ePerIsoK70; } - nRead *= pow(2.f, nreadIso); eperIsoModel *= pow(2.f, eperIso); -#ifdef PIXELSHIFTDEV - if(adaptive && experimental0) { - eperIso = eperIsoModel * sqrtf(100.f / (rawWpCorrection * idata->getISOSpeed())); - } else { - eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); - } -#else eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); -#endif -#ifdef PIXELSHIFTDEV - std::cout << "WL: " << c_white[0] << " BL: " << c_black[0] << " ePerIso multiplicator: " << (65535.f / (c_white[0] - c_black[0])) << std::endl; -#endif const float eperIsoRed = (eperIso / scale_mul[0]) * (65535.f / (c_white[0] - c_black[0])); const float eperIsoGreen = (eperIso * scaleGreen) * (65535.f / (c_white[1] - c_black[1])); const float eperIsoBlue = (eperIso / scale_mul[2]) * (65535.f / (c_white[2] - c_black[2])); @@ -708,44 +551,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const float clippedRed = 65535.f / scale_mul[0]; const float clippedBlue = 65535.f / scale_mul[2]; - prnu /= 100.f; - stddevFactorGreen *= stddevFactorGreen; - stddevFactorRed *= stddevFactorRed; - stddevFactorBlue *= stddevFactorBlue; - - nRead *= nRead; - // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel - const float motionThreshold = 1.f - (motion / 100.f); - // For shades of green motion indicators -#ifdef PIXELSHIFTDEV - const float blendFactor = ((adaptive || motion == 0.f) ? 1.f : 1.f / (1.f - motionThreshold)); -#endif - int offsX = 0, offsY = 0; - - if(!bayerParams.pixelShiftMedian || !adaptive) { - // We have to adjust the offsets for the selected subframe we use for areas with motion - switch (frame) { - case 0: - offsX = offsY = 0; - break; - - case 1: - offsX = 0; - offsY = 1; - break; - - case 2: - offsX = offsY = 1; - break; - - case 3: - offsX = 1; - offsY = 0; - } - } - // calculate average green brightness for each frame float greenBrightness[4] = {1.f, 1.f, 1.f, 1.f}; float redBrightness[4] = {1.f, 1.f, 1.f, 1.f}; @@ -795,6 +602,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA for(int j = winx + 1, offset = FC(i, j) & 1; j < winw - 1; ++j, offset ^= 1) { (*histogreenThr[1 - offset])[(*rawDataFrames[1 - offset])[i - offset + 1][j]]++; (*histogreenThr[3 - offset])[(*rawDataFrames[3 - offset])[i + offset][j + 1]]++; + if(bluerow) { (*historedThr[2 - offset])[(*rawDataFrames[2 - offset])[i + 1][j - offset + 1]]++; (*histoblueThr[(offset << 1) + offset])[(*rawDataFrames[(offset << 1) + offset])[i][j + offset]]++; @@ -805,7 +613,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } } +#ifdef _OPENMP #pragma omp critical +#endif { for(int i = 0; i < 4; ++i) { (*histogreen[i]) += (*histogreenThr[i]); @@ -827,556 +637,150 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA delete histoblue[i]; delete histogreen[i]; } - -#ifdef PIXELSHIFTDEV - std::cout << "blue brightness factors by median : " << blueBrightness[0] << " " << blueBrightness[1] << " " << blueBrightness[2] << " " << blueBrightness[3] << std::endl; - std::cout << "red brightness factors by median : " << redBrightness[0] << " " << redBrightness[1] << " " << redBrightness[2] << " " << redBrightness[3] << std::endl; - std::cout << "green brightness factors by median : " << greenBrightness[0] << " " << greenBrightness[1] << " " << greenBrightness[2] << " " << greenBrightness[3] << std::endl; -#endif - } - const float thresh = adaptive ? 0.f : motionThreshold; - array2D<float> psRed(winw + 32, winh); // increase width to avoid cache conflicts - array2D<float> psG1(winw + 32, winh); - array2D<float> psG2(winw + 32, winh); - array2D<float> psBlue(winw + 32, winh); - if(!equalChannel) { - for(int i = 0; i < 4; ++i ) { + for(int i = 0; i < 4; ++i) { redBrightness[i] = blueBrightness[i] = greenBrightness[i]; } } -// fill channels psRed, psG1, psG2 and psBlue -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) -#endif - for(int i = winy + 1; i < winh - 1; ++i) { - float *greenDest1 = psG1[i]; - float *greenDest2 = psG2[i]; - float *nonGreenDest0 = psRed[i]; - float *nonGreenDest1 = psBlue[i]; - float ngbright[2][4] = {{redBrightness[0],redBrightness[1],redBrightness[2],redBrightness[3]}, - {blueBrightness[0],blueBrightness[1],blueBrightness[2],blueBrightness[3]} - }; - int ng = 0; - int j = winx + 1; - int c = FC(i, j); - - if ((c + FC(i, j + 1)) == 3) { - // row with blue pixels => swap destination pointers for non green pixels - std::swap(nonGreenDest0, nonGreenDest1); - std::swap(greenDest1, greenDest2); - ng ^= 1; - } - - // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop - unsigned int offset = c & 1; - - for(; j < winw - 1; ++j) { - // store the values from the 4 frames into 4 different temporary planes - greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset]; - greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset]; - nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset] * ngbright[ng][(offset << 1) + offset]; - nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1] * ngbright[ng^1][2 - offset]; - offset ^= 1; // 0 => 1 or 1 => 0 - } - } - -// now that the temporary planes are filled for easy access we do the motion detection -#ifdef PIXELSHIFTDEV - int sum[2] = {0}; - float pixelcount = ((winh - (border + offsY) - (winy + border - offsY)) * (winw - (border + offsX) - (winx + border - offsX))) / 2.f; -#endif - - array2D<float> psMask(winw, winh); + if(adaptive) { + // fill channels psRed, psG1, psG2 and psBlue + array2D<float> psRed(winw + 32, winh); // increase width to avoid cache conflicts + array2D<float> psG1(winw + 32, winh); + array2D<float> psG2(winw + 32, winh); + array2D<float> psBlue(winw + 32, winh); #ifdef _OPENMP - #pragma omp parallel -#endif - { -#ifdef PIXELSHIFTDEV - int sumThr[2] = {0}; -#endif -#ifdef _OPENMP - #pragma omp for schedule(dynamic,16) nowait -#endif - - for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { -#ifdef PIXELSHIFTDEV - float *greenDest = green[i + offsY]; - float *redDest = red[i + offsY]; - float *blueDest = blue[i + offsY]; -#endif - int j = winx + border - offsX; - -#ifdef PIXELSHIFTDEV - float greenDifMax[gridSize]; // Here we store the maximum differences per Column - - // green channel motion detection checks the grid around the pixel for differences in green channels - - if(detectMotion || (adaptive && checkGreen)) { - if(gridSize == 3) { - // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - } else if(gridSize == 5) { - // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[2] = std::max({greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[3] = std::max({greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - } else if(gridSize == 7) { - // compute maximum of differences for first six columns of 7x7 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 3][j - 3], psG2[i - 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j - 3], psG2[i - 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 3], psG2[i - 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 3], psG2[ i ][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 3], psG2[i + 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 3], psG2[i + 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j - 3], psG2[i + 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 3][j - 2], psG2[i - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j - 2], psG2[i + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[2] = std::max({greenDiff(psG1[i - 3][j - 1], psG2[i - 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j - 1], psG2[i + 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[3] = std::max({greenDiff(psG1[i - 3][ j ], psG2[i - 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][ j ], psG2[i + 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[4] = std::max({greenDiff(psG1[i - 3][j + 1], psG2[i - 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j + 1], psG2[i + 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[5] = std::max({greenDiff(psG1[i - 3][j + 2], psG2[i - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j + 2], psG2[i + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - } - - } - - // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 - int lastIndex = gridSize - 1; - float korr = 0.f; - bool blueRow = false; + #pragma omp parallel for schedule(dynamic,16) #endif + for(int i = winy + 1; i < winh - 1; ++i) { + float *greenDest1 = psG1[i]; + float *greenDest2 = psG2[i]; + float *nonGreenDest0 = psRed[i]; + float *nonGreenDest1 = psBlue[i]; + float ngbright[2][4] = {{redBrightness[0], redBrightness[1], redBrightness[2], redBrightness[3]}, + {blueBrightness[0], blueBrightness[1], blueBrightness[2], blueBrightness[3]} + }; + int ng = 0; + int j = winx + 1; int c = FC(i, j); -#ifdef PIXELSHIFTDEV - if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { + if((c + FC(i, j + 1)) == 3) { // row with blue pixels => swap destination pointers for non green pixels - blueRow = true; + std::swap(nonGreenDest0, nonGreenDest1); + std::swap(greenDest1, greenDest2); + ng ^= 1; } -#endif + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop unsigned int offset = c & 1; - for(; j < winw - (border + offsX); ++j) { + for(; j < winw - 1; ++j) { + // store the values from the 4 frames into 4 different temporary planes + greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset]; + greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset]; + nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset] * ngbright[ng][(offset << 1) + offset]; + nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1] * ngbright[ng ^ 1][2 - offset]; + offset ^= 1; // 0 => 1 or 1 => 0 + } + } + + // now that the temporary planes are filled for easy access we do the motion detection + array2D<float> psMask(winw, winh); + + int offsX = 0, offsY = 0; + + if(!bayerParams.pixelShiftMedian) { + // We have to adjust the offsets for the selected subframe we use for areas with motion + switch(frame) { + case 0: + offsX = offsY = 0; + break; + + case 1: + offsX = 0; + offsY = 1; + break; + + case 2: + offsX = offsY = 1; + break; + + case 3: + offsX = 1; + offsY = 0; + } + } + + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { + for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { psMask[i][j] = 1.f; - offset ^= 1; // 0 => 1 or 1 => 0 - -#ifdef PIXELSHIFTDEV - if(detectMotion || (adaptive && checkGreen)) { - bool skipNext = false; - float gridMax = 0.f; -#else - if(adaptive && checkGreen) { - float gridMax; -#endif - -#ifdef PIXELSHIFTDEV - - if(gridSize < 2) { - // compute difference for current pixel and skip next pixel, that's roughly the method from dcrawps -#endif - gridMax = greenDiff(psG1[i][j], psG2[i][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); -#ifdef PIXELSHIFTDEV - - skipNext = skip; - } else if(gridSize == 3) { - // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); - // adjust index for next column - lastIndex ++; - lastIndex = lastIndex == gridSize ? 0 : lastIndex; - } else if(gridSize == 5) { - // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); - // adjust index for next column - lastIndex ++; - lastIndex = lastIndex == gridSize ? 0 : lastIndex; - } else if(gridSize == 7) { - // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 3][j + 3], psG2[i - 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j + 3], psG2[i - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 3], psG2[i - 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 3], psG2[ i ][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 3], psG2[i + 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 3], psG2[i + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j + 3], psG2[i + 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); - // adjust index for next column - lastIndex ++; - lastIndex = lastIndex == gridSize ? 0 : lastIndex; - } - - if(!adaptive) { - // increase motion detection dependent on brightness - korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; - } - - if (gridMax > thresh - korr) { -#else - if (gridMax > thresh) { - -#endif - -#ifdef PIXELSHIFTDEV - sumThr[offset] ++; - - if(nOf3x3) { -#endif - psMask[i][j] = greenWeight; -#ifdef PIXELSHIFTDEV - } - - else if((offset == (frame & 1)) && checkNonGreenVertical) { - if(frame > 1) { - green[i + offsY][j + offsX] = blueRow ? psG1[i][j] : psG2[i][j]; - } else { - green[i + offsY][j + offsX] = blueRow ? psG2[i][j] : psG1[i][j];; - } - - } else { - // at least one of the tested green pixels of the grid is detected as motion - paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); - - if(skipNext) { - // treat the horizontally next pixel also as motion - j++; - paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); - } - } - -#endif - // do not set the motion pixel values. They have already been set by demosaicer or showMotion + if(checkGreen) { + if(greenDiff(psG1[i][j], psG2[i][j], stddevFactorGreen, eperIsoGreen, nRead, prnu) > 0.f) { + psMask[i][j] = greenWeight; + // do not set the motion pixel values. They have already been set by demosaicer continue; } } - if(adaptive) { - if(checkNonGreenCross) { - // check red cross - float redTop = psRed[i - 1][ j ]; - float redLeft = psRed[ i ][j - 1]; - float redCentre = psRed[ i ][ j ]; - float redRight = psRed[ i ][j + 1]; - float redBottom = psRed[i + 1][ j ]; - float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, clippedRed, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + if(checkNonGreenCross) { + // check red cross + float redTop = psRed[i - 1][ j ]; + float redLeft = psRed[ i ][j - 1]; + float redCentre = psRed[ i ][ j ]; + float redRight = psRed[ i ][j + 1]; + float redBottom = psRed[i + 1][ j ]; + float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, clippedRed, stddevFactorRed, eperIsoRed, nRead, prnu); - if(redDiff > 0.f) { -#ifdef PIXELSHIFTDEV - - if(nOf3x3) { -#endif - psMask[i][j] = redBlueWeight; -#ifdef PIXELSHIFTDEV - } else { - paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); - } - -#endif - continue; - } - - // check blue cross - float blueTop = psBlue[i - 1][ j ]; - float blueLeft = psBlue[ i ][j - 1]; - float blueCentre = psBlue[ i ][ j ]; - float blueRight = psBlue[ i ][j + 1]; - float blueBottom = psBlue[i + 1][ j ]; - float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, clippedBlue, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiff > 0.f) { -#ifdef PIXELSHIFTDEV - - if(nOf3x3) { -#endif - psMask[i][j] = redBlueWeight; -#ifdef PIXELSHIFTDEV - } else { - paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); - } - -#endif - continue; - - } + if(redDiff > 0.f) { + psMask[i][j] = redBlueWeight; + continue; } -#ifdef PIXELSHIFTDEV + // check blue cross + float blueTop = psBlue[i - 1][ j ]; + float blueLeft = psBlue[ i ][j - 1]; + float blueCentre = psBlue[ i ][ j ]; + float blueRight = psBlue[ i ][j + 1]; + float blueBottom = psBlue[i + 1][ j ]; + float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, clippedBlue, stddevFactorBlue, eperIsoBlue, nRead, prnu); - if(checkNonGreenHorizontal) { - float redLeft = psRed[ i ][j - 1]; - float redCentre = psRed[ i ][ j ]; - float redRight = psRed[ i ][j + 1]; - - float redDiffLeft = redLeft - redCentre; - float redDiffRight = redRight - redCentre; - - if(redDiffLeft * redDiffRight >= 0.f) { - float redAvg = (redRight + redLeft) / 2.f; - float redDiffHor = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - - if(redDiffHor > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, redDiffHor, showOnlyMask, redDest, blueDest, greenDest); - } - - continue; - } - } - - float blueLeft = psBlue[ i ][j - 1]; - float blueCentre = psBlue[ i ][ j ]; - float blueRight = psBlue[ i ][j + 1]; - - float blueDiffLeft = blueLeft - blueCentre; - float blueDiffRight = blueRight - blueCentre; - - if(blueDiffLeft * blueDiffRight >= 0.f) { - float blueAvg = (blueRight + blueLeft) / 2.f; - float blueDiffHor = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiffHor > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, blueDiffHor, showOnlyMask, blueDest, redDest, greenDest); - } - - continue; - } - } + if(blueDiff > 0.f) { + psMask[i][j] = redBlueWeight; + continue; } - - if(checkNonGreenVertical) { - // check red vertically - float redTop = psRed[i - 1][ j ]; - float redCentre = psRed[ i ][ j ]; - float redBottom = psRed[i + 1][ j ]; - - float redDiffTop = redTop - redCentre; - float redDiffBottom = redBottom - redCentre; - - if(redDiffTop * redDiffBottom >= 0.f) { - float redAvg = (redTop + redBottom) / 2.f; - float redDiff = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - - if(redDiff > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); - } - - continue; - } - } - - // check blue vertically - float blueTop = psBlue[i - 1][ j ]; - float blueCentre = psBlue[ i ][ j ]; - float blueBottom = psBlue[i + 1][ j ]; - - float blueDiffTop = blueTop - blueCentre; - float blueDiffBottom = blueBottom - blueCentre; - - if(blueDiffTop * blueDiffBottom >= 0.f) { - float blueAvg = (blueTop + blueBottom) / 2.f; - float blueDiff = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiff > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); - } - - continue; - } - } - } - - if(checkNonGreenAmaze) { - // check current pixel against amaze - float redCentre = psRed[ i ][ j ]; - float redAmaze = red[i + offsY][j + offsX]; - - float redDiffAmaze = nonGreenDiff(redCentre, redAmaze, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - - if(redDiffAmaze > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, redDiffAmaze, showOnlyMask, redDest, blueDest, greenDest); - } - - continue; - } - - float blueCentre = psBlue[ i ][ j ]; - float blueAmaze = blue[i + offsY][j + offsX]; - - float blueDiffAmaze = nonGreenDiff(blueCentre, blueAmaze, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiffAmaze > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, blueDiffAmaze, showOnlyMask, blueDest, redDest, greenDest); - } - - continue; - } - } - - if(checkNonGreenCross2) { // for green amaze - float greenCentre = (psG1[ i ][ j ] + psG2[ i ][ j ]) / 2.f; - float greenAmaze = green[i + offsY][j + offsX]; - float greenDiffAmaze = nonGreenDiff(greenCentre, greenAmaze, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); - - if(greenDiffAmaze > 0.f) { - if(nOf3x3) { - psMask[i][j] = greenWeight; - } else { - paintMotionMask(j + offsX, showMotion, greenDiffAmaze, showOnlyMask, greenDest, redDest, blueDest); - } - - continue; - } - } - - if(experimental0) { // for experiments - - } - -#endif } if(showOnlyMask) { // we want only motion mask => paint areas without motion in pure black red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; - } else if(!(adaptive && nOf3x3)) { - // no motion detected, replace the a priori demosaiced values by the pixelshift combined values - red[i + offsY][j + offsX] = psRed[i][j]; - green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; - blue[i + offsY][j + offsX] = psBlue[i][j]; } } } -#ifdef PIXELSHIFTDEV - -#ifdef _OPENMP - #pragma omp critical -#endif - { - sum[0] += sumThr[0]; - sum[1] += sumThr[1]; - } -#endif - } - - -#ifdef PIXELSHIFTDEV - float percent0 = 100.f * sum[0] / pixelcount; - float percent1 = 100.f * sum[1] / pixelcount; - - std::cout << fileName << " : Green detections at stddev " << std::setprecision( 2 ) << bayerParams.pixelShiftStddevFactorGreen << " : Frame 1/3 : " << std::setprecision( 6 ) << sum[0] << " (" << percent0 << "%)" << " Frame 2/4 : " << sum[1] << " (" << percent1 << "%)" << std::endl; -#endif - - if(adaptive && nOf3x3) { if(blurMap) { +#ifdef _OPENMP #pragma omp parallel +#endif { gaussianBlur(psMask, psMask, winw, winh, sigma); } } - array2D<uint8_t> mask(W, H, ARRAY2D_CLEAR_DATA); + array2D<uint8_t> mask(winw, winh, ARRAY2D_CLEAR_DATA); +#ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) +#endif for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { int j = winx + border - offsX; @@ -1404,18 +808,20 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } if(holeFill) { - array2D<uint8_t> maskInv(W, H); + array2D<uint8_t> maskInv(winw, winh); invertMask(winx + border - offsX, winw - (border + offsX), winy + border - offsY, winh - (border + offsY), mask, maskInv); floodFill4(winx + border - offsX, winw - (border + offsX), winy + border - offsY, winh - (border + offsY), maskInv); xorMasks(winx + border - offsX, winw - (border + offsX), winy + border - offsY, winh - (border + offsY), maskInv, mask); } - +#ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) +#endif for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { #ifdef __SSE2__ + // pow() is expensive => precalculate blend factor using SSE if(smoothTransitions) { // vfloat onev = F2V(1.f); vfloat smoothv = F2V(smoothFactor); @@ -1440,12 +846,13 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { if(mask[i][j] == 255) { - paintMotionMask(j + offsX, showMotion, 0.5f, showOnlyMask, greenDest, redDest, blueDest); + paintMotionMask(j + offsX, showMotion, showOnlyMask, greenDest, redDest, blueDest); } else if(showOnlyMask) { // we want only motion mask => paint areas without motion in pure black redDest[j + offsX] = greenDest[j + offsX] = blueDest[j + offsX] = 0.f; } else { if(smoothTransitions) { #ifdef __SSE2__ + // use precalculated blend factor const float blend = psMask[i][j]; #else const float blend = smoothFactor == 0.f ? 1.f : pow_F(std::max(psMask[i][j] - 1.f, 0.f), smoothFactor); @@ -1461,6 +868,39 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } } } + } else { + // motion detection off => combine the 4 raw frames + float ngbright[2][4] = {{redBrightness[0], redBrightness[1], redBrightness[2], redBrightness[3]}, + {blueBrightness[0], blueBrightness[1], blueBrightness[2], blueBrightness[3]} + }; +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for(int i = winy + 1; i < winh - 1; ++i) { + float *nonGreenDest0 = red[i]; + float *nonGreenDest1 = blue[i]; + int ng = 0; + int j = winx + 1; + int c = FC(i, j); + + if((c + FC(i, j + 1)) == 3) { + // row with blue pixels => swap destination pointers for non green pixels + std::swap(nonGreenDest0, nonGreenDest1); + ng ^= 1; + } + + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = c & 1; + + for(; j < winw - 1; ++j) { + // set red, green and blue values + green[i][j] = ((*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset] + (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset]) * 0.5f; + nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset] * ngbright[ng][(offset << 1) + offset]; + nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1] * ngbright[ng ^ 1][2 - offset]; + offset ^= 1; // 0 => 1 or 1 => 0 + } + } } if(plistener) { From 486d51e434c96eaf596e4ee9a55b4b32ef3e2dd8 Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Tue, 30 May 2017 18:44:03 +0200 Subject: [PATCH 25/32] Reduced memory usage of Pixel Shift motion detection by ~ width * height * 8 byte --- rtengine/pixelshift.cc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 71212b0b3..89571ec15 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -647,10 +647,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA if(adaptive) { - // fill channels psRed, psG1, psG2 and psBlue + // fill channels psRed and psBlue array2D<float> psRed(winw + 32, winh); // increase width to avoid cache conflicts - array2D<float> psG1(winw + 32, winh); - array2D<float> psG2(winw + 32, winh); array2D<float> psBlue(winw + 32, winh); #ifdef _OPENMP @@ -658,8 +656,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #endif for(int i = winy + 1; i < winh - 1; ++i) { - float *greenDest1 = psG1[i]; - float *greenDest2 = psG2[i]; float *nonGreenDest0 = psRed[i]; float *nonGreenDest1 = psBlue[i]; float ngbright[2][4] = {{redBrightness[0], redBrightness[1], redBrightness[2], redBrightness[3]}, @@ -672,7 +668,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA if((c + FC(i, j + 1)) == 3) { // row with blue pixels => swap destination pointers for non green pixels std::swap(nonGreenDest0, nonGreenDest1); - std::swap(greenDest1, greenDest2); ng ^= 1; } @@ -680,9 +675,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA unsigned int offset = c & 1; for(; j < winw - 1; ++j) { - // store the values from the 4 frames into 4 different temporary planes - greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset]; - greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset]; + // store the non green values from the 4 frames into 2 temporary planes nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset] * ngbright[ng][(offset << 1) + offset]; nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1] * ngbright[ng ^ 1][2 - offset]; offset ^= 1; // 0 => 1 or 1 => 0 @@ -722,11 +715,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #endif for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { - for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = FC(i, winx + border - offsX) & 1; + + for(int j = winx + border - offsX; j < winw - (border + offsX); ++j, offset ^= 1) { psMask[i][j] = 1.f; if(checkGreen) { - if(greenDiff(psG1[i][j], psG2[i][j], stddevFactorGreen, eperIsoGreen, nRead, prnu) > 0.f) { + if(greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset], (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset], stddevFactorGreen, eperIsoGreen, nRead, prnu) > 0.f) { psMask[i][j] = greenWeight; // do not set the motion pixel values. They have already been set by demosaicer continue; @@ -844,7 +840,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA float *redDest = red[i + offsY]; float *blueDest = blue[i + offsY]; - for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = FC(i, winx + border - offsX) & 1; + + for(int j = winx + border - offsX; j < winw - (border + offsX); ++j, offset ^= 1) { if(mask[i][j] == 255) { paintMotionMask(j + offsX, showMotion, showOnlyMask, greenDest, redDest, blueDest); } else if(showOnlyMask) { // we want only motion mask => paint areas without motion in pure black @@ -858,11 +857,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const float blend = smoothFactor == 0.f ? 1.f : pow_F(std::max(psMask[i][j] - 1.f, 0.f), smoothFactor); #endif redDest[j + offsX] = intp(blend, redDest[j + offsX], psRed[i][j] ); - greenDest[j + offsX] = intp(blend, greenDest[j + offsX], (psG1[i][j] + psG2[i][j]) * 0.5f); + greenDest[j + offsX] = intp(blend, greenDest[j + offsX], ((*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset] + (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset]) * 0.5f); blueDest[j + offsX] = intp(blend, blueDest[j + offsX], psBlue[i][j]); } else { redDest[j + offsX] = psRed[i][j]; - greenDest[j + offsX] = (psG1[i][j] + psG2[i][j]) * 0.5f; + greenDest[j + offsX] = ((*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset] + (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset]) * 0.5f; blueDest[j + offsX] = psBlue[i][j]; } } From e8e01c3af1d250064a80648dfa47fee620f231b2 Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Tue, 30 May 2017 19:45:17 +0200 Subject: [PATCH 26/32] pixelshift: skip demosaic when 'Show only motion mask' is enabled --- rtengine/pixelshift.cc | 74 ++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 89571ec15..9082ea4c5 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -316,53 +316,57 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA bayerParams.setPixelShiftDefaults(); bayerParams.pixelShiftEqualBright = pixelShiftEqualBright; } else if(bayerParams.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Off) { - bayerParams.pixelShiftMotion = 0; bayerParams.pixelShiftAutomatic = false; bayerParams.pixelShiftShowMotion = false; } - if((bayerParams.pixelShiftMotion > 0 || bayerParams.pixelShiftAutomatic)) { - if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction - if(bayerParams.pixelShiftLmmse) { - lmmse_interpolate_omp(winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.lmmse_iterations); - } else { - amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[0]), red, green, blue); - } + const bool showMotion = bayerParams.pixelShiftShowMotion; + const bool showOnlyMask = bayerParams.pixelShiftShowMotionMaskOnly && showMotion; - multi_array2D<float, 3> redTmp(winw, winh); - multi_array2D<float, 3> greenTmp(winw, winh); - multi_array2D<float, 3> blueTmp(winw, winh); - - for(int i = 0; i < 3; i++) { + if(bayerParams.pixelShiftAutomatic) { + if(!showOnlyMask) { + if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction if(bayerParams.pixelShiftLmmse) { - lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.lmmse_iterations); + lmmse_interpolate_omp(winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.lmmse_iterations); } else { - amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i]); - } - } - -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) -#endif - - for(int i = winy + border; i < winh - border; i++) { - for(int j = winx + border; j < winw - border; j++) { - red[i][j] = median(red[i][j], redTmp[0][i + 1][j], redTmp[1][i + 1][j + 1], redTmp[2][i][j + 1]); + amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[0]), red, green, blue); } - for(int j = winx + border; j < winw - border; j++) { - green[i][j] = median(green[i][j], greenTmp[0][i + 1][j], greenTmp[1][i + 1][j + 1], greenTmp[2][i][j + 1]); + multi_array2D<float, 3> redTmp(winw, winh); + multi_array2D<float, 3> greenTmp(winw, winh); + multi_array2D<float, 3> blueTmp(winw, winh); + + for(int i = 0; i < 3; i++) { + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.lmmse_iterations); + } else { + amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i]); + } } - for(int j = winx + border; j < winw - border; j++) { - blue[i][j] = median(blue[i][j], blueTmp[0][i + 1][j], blueTmp[1][i + 1][j + 1], blueTmp[2][i][j + 1]); + #ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) + #endif + + for(int i = winy + border; i < winh - border; i++) { + for(int j = winx + border; j < winw - border; j++) { + red[i][j] = median(red[i][j], redTmp[0][i + 1][j], redTmp[1][i + 1][j + 1], redTmp[2][i][j + 1]); + } + + for(int j = winx + border; j < winw - border; j++) { + green[i][j] = median(green[i][j], greenTmp[0][i + 1][j], greenTmp[1][i + 1][j + 1], greenTmp[2][i][j + 1]); + } + + for(int j = winx + border; j < winw - border; j++) { + blue[i][j] = median(blue[i][j], blueTmp[0][i + 1][j], blueTmp[1][i + 1][j + 1], blueTmp[2][i][j + 1]); + } } - } - } else { - if(bayerParams.pixelShiftLmmse) { - lmmse_interpolate_omp(winw, winh, rawData, red, green, blue, bayerParams.lmmse_iterations); } else { - amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue); + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(winw, winh, rawData, red, green, blue, bayerParams.lmmse_iterations); + } else { + amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue); + } } } } else if(bayerParams.pixelShiftMotionCorrectionMethod != RAWParams::BayerSensor::Off) { @@ -373,8 +377,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } } - const bool showMotion = bayerParams.pixelShiftShowMotion; - const bool showOnlyMask = bayerParams.pixelShiftShowMotionMaskOnly && showMotion; const bool adaptive = bayerParams.pixelShiftAutomatic; constexpr float stddevFactorGreen = 25.f; constexpr float stddevFactorRed = 25.f; From 28fee5e72b02e75aba9acc480b4f222c47cd204f Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Tue, 30 May 2017 19:48:06 +0200 Subject: [PATCH 27/32] fix wrong indentation --- rtengine/pixelshift.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 9082ea4c5..e7d6b86c7 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -344,9 +344,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } } - #ifdef _OPENMP +#ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) - #endif +#endif for(int i = winy + border; i < winh - border; i++) { for(int j = winx + border; j < winw - border; j++) { From 8a9c044d5623032579696529762c64d56759044f Mon Sep 17 00:00:00 2001 From: Desmis <jdesmis@gmail.com> Date: Wed, 31 May 2017 14:38:16 +0200 Subject: [PATCH 28/32] Prevent curves to jump with Brightness algoritm --- rtengine/improcfun.cc | 2707 +++++++++++++++++++------------------- rtgui/colorappearance.cc | 468 +++---- 2 files changed, 1605 insertions(+), 1570 deletions(-) diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index c68158634..96920c3da 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -78,6 +78,7 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, monitorTransform = nullptr; cmsHPROFILE monitor = nullptr; + if (!monitorProfile.empty()) { #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB monitor = ICCStore::getInstance()->getProfile (monitorProfile); @@ -90,32 +91,37 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, MyMutex::MyLock lcmsLock (*lcmsMutex); cmsUInt32Number flags; - cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); + cmsHPROFILE iprof = cmsCreateLab4Profile (nullptr); bool softProofCreated = false; if (softProof) { cmsHPROFILE oprof = nullptr; + if (!settings->printerProfile.empty()) { - oprof = ICCStore::getInstance()->getProfile(settings->printerProfile); + oprof = ICCStore::getInstance()->getProfile (settings->printerProfile); } if (oprof) { // NOCACHE is for thread safety, NOOPTIMIZE for precision flags = cmsFLAGS_SOFTPROOFING | cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (settings->printerBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } + if (gamutCheck) { flags |= cmsFLAGS_GAMUTCHECK; } - monitorTransform = cmsCreateProofingTransform( - iprof, TYPE_Lab_FLT, - monitor, TYPE_RGB_8, - oprof, - monitorIntent, settings->printerIntent, - flags - ); + + monitorTransform = cmsCreateProofingTransform ( + iprof, TYPE_Lab_FLT, + monitor, TYPE_RGB_8, + oprof, + monitorIntent, settings->printerIntent, + flags + ); + if (monitorTransform) { softProofCreated = true; } @@ -124,13 +130,15 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, 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); + cmsCloseProfile (iprof); } } @@ -145,19 +153,19 @@ void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const Pro int W = original->getWidth(); int H = original->getHeight(); - float lumimulf[3] = {static_cast<float>(lumimul[0]), static_cast<float>(lumimul[1]), static_cast<float>(lumimul[2])}; + float lumimulf[3] = {static_cast<float> (lumimul[0]), static_cast<float> (lumimul[1]), static_cast<float> (lumimul[2])}; // calculate histogram of the y channel needed for contrast curve calculation in exposure adjustments histogram.clear(); - if(multiThread) { + if (multiThread) { #ifdef _OPENMP - const int numThreads = min(max(W * H / (int)histogram.getSize(), 1), omp_get_max_threads()); + const int numThreads = min (max (W * H / (int)histogram.getSize(), 1), omp_get_max_threads()); #pragma omp parallel num_threads(numThreads) if(numThreads>1) #endif { - LUTu hist(histogram.getSize()); + LUTu hist (histogram.getSize()); hist.clear(); #ifdef _OPENMP #pragma omp for nowait @@ -166,9 +174,9 @@ void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const Pro for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { - float r = original->r(i, j); - float g = original->g(i, j); - float b = original->b(i, j); + float r = original->r (i, j); + float g = original->g (i, j); + float b = original->b (i, j); int y = (lumimulf[0] * r + lumimulf[1] * g + lumimulf[2] * b); hist[y]++; @@ -182,15 +190,15 @@ void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const Pro } #ifdef _OPENMP - static_cast<void>(numThreads); // to silence cppcheck warning + static_cast<void> (numThreads); // to silence cppcheck warning #endif } else { for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { - float r = original->r(i, j); - float g = original->g(i, j); - float b = original->b(i, j); + float r = original->r (i, j); + float g = original->g (i, j); + float b = original->b (i, j); int y = (lumimulf[0] * r + lumimulf[1] * g + lumimulf[2] * b); histogram[y]++; @@ -204,7 +212,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2, const ColorAppearance & customColCurve3, LUTu & histLCAM, LUTu & histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, bool execsharp, double &d, int scalecd, int rtt) { - if(params->colorappearance.enabled) { + if (params->colorappearance.enabled) { //int lastskip; //if(rtt==1) {lastskip=scalecd;} //not for Rtthumbnail @@ -217,15 +225,15 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh bool jp = false; //preparate for histograms CIECAM - if(pW != 1) { //only with improccoordinator - dLcurve(65536, 0); + if (pW != 1) { //only with improccoordinator + dLcurve (65536, 0); dLcurve.clear(); - hist16JCAM(65536, 0); + hist16JCAM (65536, 0); hist16JCAM.clear(); for (int i = 0; i < 32768; i++) { //# 32768*1.414 approximation maxi for chroma float val = (double)i / 32767.0; - dLcurve[i] = CLIPD(val); + dLcurve[i] = CLIPD (val); } } @@ -233,14 +241,14 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh LUTu hist16_CCAM; bool chropC = false; - if(pW != 1) { //only with improccoordinator - dCcurve(65536, 0); - hist16_CCAM(65536); + if (pW != 1) { //only with improccoordinator + dCcurve (65536, 0); + hist16_CCAM (65536); hist16_CCAM.clear(); for (int i = 0; i < 48000; i++) { //# 32768*1.414 approximation maxi for chroma float valc = (double)i / 47999.0; - dCcurve[i] = CLIPD(valc); + dCcurve[i] = CLIPD (valc); } } @@ -267,22 +275,22 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh ColorTemp::temp2mulxyz (params->wb.temperature, params->wb.green, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB //viewing condition for surround - if(params->colorappearance.surround == "Average") { + if (params->colorappearance.surround == "Average") { f = 1.00; c = 0.69; nc = 1.00; f2 = 1.0, c2 = 0.69, nc2 = 1.0; - } else if(params->colorappearance.surround == "Dim") { + } else if (params->colorappearance.surround == "Dim") { f2 = 0.9; c2 = 0.59; nc2 = 0.9; f = 1.0, c = 0.69, nc = 1.0; - } else if(params->colorappearance.surround == "Dark") { + } else if (params->colorappearance.surround == "Dark") { f2 = 0.8; c2 = 0.525; nc2 = 0.8; f = 1.0, c = 0.69, nc = 1.0; - } else if(params->colorappearance.surround == "ExtremelyDark") { + } else if (params->colorappearance.surround == "ExtremelyDark") { f2 = 0.8; c2 = 0.41; nc2 = 0.8; @@ -290,7 +298,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh } //scene condition for surround - if(params->colorappearance.surrsource) { + if (params->colorappearance.surrsource) { f = 0.85; // if user => source image has surround very dark c = 0.55; nc = 0.85; @@ -299,12 +307,12 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh //with which algorithme if (params->colorappearance.algo == "JC") { alg = 0; - } else if(params->colorappearance.algo == "JS") { + } else if (params->colorappearance.algo == "JS") { alg = 1; - } else if(params->colorappearance.algo == "QM") { + } else if (params->colorappearance.algo == "QM") { alg = 2; algepd = true; - } else if(params->colorappearance.algo == "ALL") { + } else if (params->colorappearance.algo == "ALL") { alg = 3; algepd = true; } @@ -313,35 +321,35 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh bool needQ = (alg == 2 || alg == 3); //settings white point of output device - or illuminant viewing - if(settings->viewingdevice == 0) { + if (settings->viewingdevice == 0) { xwd = 96.42; //5000K ywd = 100.0; zwd = 82.52; - } else if(settings->viewingdevice == 1) { + } else if (settings->viewingdevice == 1) { xwd = 95.68; //5500 ywd = 100.0; zwd = 92.15; - } else if(settings->viewingdevice == 2) { + } else if (settings->viewingdevice == 2) { xwd = 95.24; //6000 ywd = 100.0; zwd = 100.81; - } else if(settings->viewingdevice == 3) { + } else if (settings->viewingdevice == 3) { xwd = 95.04; //6500 ywd = 100.0; zwd = 108.88; - } else if(settings->viewingdevice == 4) { + } else if (settings->viewingdevice == 4) { xwd = 109.85; //tungsten ywd = 100.0; zwd = 35.58; - } else if(settings->viewingdevice == 5) { + } else if (settings->viewingdevice == 5) { xwd = 99.18; //fluo F2 ywd = 100.0; zwd = 67.39; - } else if(settings->viewingdevice == 6) { + } else if (settings->viewingdevice == 6) { xwd = 95.04; //fluo F7 ywd = 100.0; zwd = 108.75; - } else if(settings->viewingdevice == 7) { + } else if (settings->viewingdevice == 7) { xwd = 100.96; //fluo F11 ywd = 100.0; zwd = 64.35; @@ -349,32 +357,32 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh //settings mean Luminance Y of output device or viewing - if(settings->viewingdevicegrey == 0) { + if (settings->viewingdevicegrey == 0) { yb2 = 5.0; - } else if(settings->viewingdevicegrey == 1) { + } else if (settings->viewingdevicegrey == 1) { yb2 = 10.0; - } else if(settings->viewingdevicegrey == 2) { + } else if (settings->viewingdevicegrey == 2) { yb2 = 15.0; - } else if(settings->viewingdevicegrey == 3) { + } else if (settings->viewingdevicegrey == 3) { yb2 = 18.0; - } else if(settings->viewingdevicegrey == 4) { + } else if (settings->viewingdevicegrey == 4) { yb2 = 23.0; - } else if(settings->viewingdevicegrey == 5) { + } else if (settings->viewingdevicegrey == 5) { yb2 = 30.0; - } else if(settings->viewingdevicegrey == 6) { + } else if (settings->viewingdevicegrey == 6) { yb2 = 40.0; } //La and la2 = ambiant luminosity scene and viewing - la = double(params->colorappearance.adapscen); + la = double (params->colorappearance.adapscen); - if(pwb == 2) { - if(params->colorappearance.autoadapscen) { + if (pwb == 2) { + if (params->colorappearance.autoadapscen) { la = adap; } } - la2 = double(params->colorappearance.adaplum); + la2 = double (params->colorappearance.adaplum); // level of adaptation double deg = (params->colorappearance.degree) / 100.0; @@ -391,20 +399,20 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh float hue = params->colorappearance.colorh; double rstprotection = 100. - params->colorappearance.rstprotection; - if(schr > 0.0) { + if (schr > 0.0) { schr = schr / 2.0f; //divide sensibility for saturation } // extracting datas from 'params' to avoid cache flush (to be confirmed) ColorAppearanceParams::eTCModeId curveMode = params->colorappearance.curveMode; ColorAppearanceParams::eTCModeId curveMode2 = params->colorappearance.curveMode2; - bool hasColCurve1 = bool(customColCurve1); - bool hasColCurve2 = bool(customColCurve2); + bool hasColCurve1 = bool (customColCurve1); + bool hasColCurve2 = bool (customColCurve2); ColorAppearanceParams::eCTCModeId curveMode3 = params->colorappearance.curveMode3; - bool hasColCurve3 = bool(customColCurve3); + bool hasColCurve3 = bool (customColCurve3); - if(CAMBrightCurveJ.dirty || CAMBrightCurveQ.dirty) { + if (CAMBrightCurveJ.dirty || CAMBrightCurveQ.dirty) { LUTu hist16J; LUTu hist16Q; @@ -428,34 +436,34 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh if (currL > 95.) { koef = 1.f; - } else if(currL > 85.) { + } else if (currL > 85.) { koef = 0.97f; - } else if(currL > 80.) { + } else if (currL > 80.) { koef = 0.93f; - } else if(currL > 70.) { + } else if (currL > 70.) { koef = 0.87f; - } else if(currL > 60.) { + } else if (currL > 60.) { koef = 0.85f; - } else if(currL > 50.) { + } else if (currL > 50.) { koef = 0.8f; - } else if(currL > 40.) { + } else if (currL > 40.) { koef = 0.75f; - } else if(currL > 30.) { + } else if (currL > 30.) { koef = 0.7f; - } else if(currL > 20.) { + } else if (currL > 20.) { koef = 0.7f; - } else if(currL > 10.) { + } else if (currL > 10.) { koef = 0.9f; - } else if(currL > 0.) { + } else if (currL > 0.) { koef = 1.0f; } if (needJ) { - hist16J[CLIP((int)((koef * lab->L[i][j])))]++; //evaluate histogram luminance L # J + hist16J[CLIP ((int) ((koef * lab->L[i][j])))]++; //evaluate histogram luminance L # J } if (needQ) { - hist16Q[CLIP((int) (32768.f * sqrt((koef * (lab->L[i][j])) / 32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L + hist16Q[CLIP ((int) (32768.f * sqrt ((koef * (lab->L[i][j])) / 32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L } sum += koef * lab->L[i][j]; //evaluate mean J to calcualte Yb @@ -467,7 +475,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh //evaluate lightness, contrast if (needJ) { if (!CAMBrightCurveJ) { - CAMBrightCurveJ(65536, 0); + CAMBrightCurveJ (65536, 0); CAMBrightCurveJ.dirty = false; } @@ -476,7 +484,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh if (needQ) { if (!CAMBrightCurveQ) { - CAMBrightCurveQ(65536, 0); + CAMBrightCurveQ (65536, 0); CAMBrightCurveQ.dirty = false; } @@ -484,40 +492,40 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh } } - if(settings->viewinggreySc == 0) { //auto + if (settings->viewinggreySc == 0) { //auto if (mean < 15.f) { yb = 3.0; - } else if(mean < 30.f) { + } else if (mean < 30.f) { yb = 5.0; - } else if(mean < 40.f) { + } else if (mean < 40.f) { yb = 10.0; - } else if(mean < 45.f) { + } else if (mean < 45.f) { yb = 15.0; - } else if(mean < 50.f) { + } else if (mean < 50.f) { yb = 18.0; - } else if(mean < 55.f) { + } else if (mean < 55.f) { yb = 23.0; - } else if(mean < 60.f) { + } else if (mean < 60.f) { yb = 30.0; - } else if(mean < 70.f) { + } else if (mean < 70.f) { yb = 40.0; - } else if(mean < 80.f) { + } else if (mean < 80.f) { yb = 60.0; - } else if(mean < 90.f) { + } else if (mean < 90.f) { yb = 80.0; } else { yb = 90.0; } } - if(settings->viewinggreySc == 1) { + if (settings->viewinggreySc == 1) { yb = 18.0; } int gamu = 0; bool highlight = params->toneCurve.hrenabled; //Get the value if "highlight reconstruction" is activated - if(params->colorappearance.gamut) { + if (params->colorappearance.gamut) { gamu = 1; //enabled gamut control } @@ -527,14 +535,14 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh double xw1, yw1, zw1, xw2, yw2, zw2; // settings of WB: scene and viewing - if(params->colorappearance.wbmodel == "RawT") { + if (params->colorappearance.wbmodel == "RawT") { xw1 = 96.46; //use RT WB; CAT 02 is used for output device (see prefreneces) yw1 = 100.0; zw1 = 82.445; 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; @@ -544,9 +552,9 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh } double cz, wh, pfl; - Ciecam02::initcam1(gamu, yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c); + Ciecam02::initcam1 (gamu, yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c); double nj, dj, nbbj, ncbj, czj, awj, flj; - Ciecam02::initcam2(gamu, yb2, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj); + Ciecam02::initcam2 (gamu, yb2, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj); @@ -579,7 +587,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh double x, y, z; double epsil = 0.0001; //convert Lab => XYZ - Color::Lab2XYZ(L, a, b, x1, y1, z1); + Color::Lab2XYZ (L, a, b, x1, y1, z1); // double J, C, h, Q, M, s, aw, fl, wh; double J, C, h, Q, M, s; @@ -594,12 +602,12 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh y = (double)y1 / 655.35; z = (double)z1 / 655.35; //process source==> normal - Ciecam02::xyz2jchqms_ciecam02( J, C, h, - Q, M, s, aw, fl, wh, - x, y, z, - xw1, yw1, zw1, - yb, la, - f, c, nc, pilot, gamu , n, nbb, ncb, pfl, cz, d ); + Ciecam02::xyz2jchqms_ciecam02 ( J, C, h, + Q, M, s, aw, fl, wh, + x, y, z, + xw1, yw1, zw1, + yb, la, + f, c, nc, pilot, gamu , n, nbb, ncb, pfl, cz, d ); Jpro = J; Cpro = C; hpro = h; @@ -612,60 +620,60 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh f_l = fl; // we cannot have all algoritms with all chroma curves - if(alg == 1) { + if (alg == 1) { // Lightness saturation - if(Jpro > 99.9f) { + if (Jpro > 99.9f) { Jpro = 99.9f; } - Jpro = (CAMBrightCurveJ[(float)(Jpro * 327.68)]) / 327.68; //ligthness CIECAM02 + contrast + Jpro = (CAMBrightCurveJ[ (float) (Jpro * 327.68)]) / 327.68; //ligthness CIECAM02 + contrast double sres; double Sp = spro / 100.0; double parsat = 1.5; //parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation) - if(schr == -100.0) { + if (schr == -100.0) { schr = -99.8; } - Ciecam02::curvecolor(schr, Sp , sres, parsat); - double coe = pow(fl, 0.25); + Ciecam02::curvecolor (schr, Sp , sres, parsat); + double coe = pow (fl, 0.25); float dred = 100.f; // in C mode float protect_red = 80.0f; // in C mode - dred = 100.0 * sqrt((dred * coe) / Qpro); - protect_red = 100.0 * sqrt((protect_red * coe) / Qpro); + dred = 100.0 * sqrt ((dred * coe) / Qpro); + protect_red = 100.0 * sqrt ((protect_red * coe) / Qpro); int sk = 0; float ko = 100.f; - Color::skinred(Jpro, hpro, sres, Sp, dred, protect_red, sk, rstprotection, ko, spro); - Qpro = ( 4.0 / c ) * sqrt( Jpro / 100.0 ) * ( aw + 4.0 ) ; + Color::skinred (Jpro, hpro, sres, Sp, dred, protect_red, sk, rstprotection, ko, spro); + Qpro = ( 4.0 / c ) * sqrt ( Jpro / 100.0 ) * ( aw + 4.0 ) ; Cpro = (spro * spro * Qpro) / (10000.0); - } else if(alg == 3 || alg == 0 || alg == 2) { + } else if (alg == 3 || alg == 0 || alg == 2) { double coef = 32760. / wh; - if(alg == 3 || alg == 2) { - if(Qpro * coef > 32767.0f) { - Qpro = (CAMBrightCurveQ[(float)32767.0f]) / coef; //brightness and contrast + if (alg == 3 || alg == 2) { + if (Qpro * coef > 32767.0f) { + Qpro = (CAMBrightCurveQ[ (float)32767.0f]) / coef; //brightness and contrast } else { - Qpro = (CAMBrightCurveQ[(float)(Qpro * coef)]) / coef; //brightness and contrast + Qpro = (CAMBrightCurveQ[ (float) (Qpro * coef)]) / coef; //brightness and contrast } } double Mp, sres; - double coe = pow(fl, 0.25); + double coe = pow (fl, 0.25); Mp = Mpro / 100.0; double parsat = 2.5; - if(mchr == -100.0) { + if (mchr == -100.0) { mchr = -99.8 ; } - if(mchr == 100.0) { + if (mchr == 100.0) { mchr = 99.9; } - if(alg == 3 || alg == 2) { - Ciecam02::curvecolor(mchr, Mp , sres, parsat); + if (alg == 3 || alg == 2) { + Ciecam02::curvecolor (mchr, Mp , sres, parsat); } else { - Ciecam02::curvecolor(0.0, Mp , sres, parsat); //colorfullness + Ciecam02::curvecolor (0.0, Mp , sres, parsat); //colorfullness } float dred = 100.f; //in C mode @@ -674,77 +682,77 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh protect_red *= coe; //M mode int sk = 0; float ko = 100.f; - Color::skinred(Jpro, hpro, sres, Mp, dred, protect_red, sk, rstprotection, ko, Mpro); + Color::skinred (Jpro, hpro, sres, Mp, dred, protect_red, sk, rstprotection, ko, Mpro); Jpro = (100.0 * Qpro * Qpro) / (wh * wh); Cpro = Mpro / coe; - spro = 100.0 * sqrt( Mpro / Qpro ); + spro = 100.0 * sqrt ( Mpro / Qpro ); - if(alg != 2) { - if(Jpro > 99.9f) { + if (alg != 2) { + if (Jpro > 99.9f) { Jpro = 99.9f; } - Jpro = (CAMBrightCurveJ[(float)(Jpro * 327.68f)]) / 327.68f; //ligthness CIECAM02 + contrast + Jpro = (CAMBrightCurveJ[ (float) (Jpro * 327.68f)]) / 327.68f; //ligthness CIECAM02 + contrast } double Cp; double Sp = spro / 100.0; parsat = 1.5; - if(schr == -100.0) { + if (schr == -100.0) { schr = -99.; } - if(schr == 100.0) { + if (schr == 100.0) { schr = 98.; } - if(alg == 3) { - Ciecam02::curvecolor(schr, Sp , sres, parsat); + if (alg == 3) { + Ciecam02::curvecolor (schr, Sp , sres, parsat); } else { - Ciecam02::curvecolor(0.0, Sp , sres, parsat); //saturation + Ciecam02::curvecolor (0.0, Sp , sres, parsat); //saturation } dred = 100.f; // in C mode protect_red = 80.0f; // in C mode - dred = 100.0 * sqrt((dred * coe) / Q); - protect_red = 100.0 * sqrt((protect_red * coe) / Q); + dred = 100.0 * sqrt ((dred * coe) / Q); + protect_red = 100.0 * sqrt ((protect_red * coe) / Q); sk = 0; - Color::skinred(Jpro, hpro, sres, Sp, dred, protect_red, sk, rstprotection, ko, spro); + Color::skinred (Jpro, hpro, sres, Sp, dred, protect_red, sk, rstprotection, ko, spro); //double Q1; - Qpro = ( 4.0 / c ) * sqrt( Jpro / 100.0 ) * ( aw + 4.0 ) ; + Qpro = ( 4.0 / c ) * sqrt ( Jpro / 100.0 ) * ( aw + 4.0 ) ; Cpro = (spro * spro * Qpro) / (10000.0); Cp = Cpro / 100.0; parsat = 1.8; //parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation : for not) - if(chr == -100.0) { + if (chr == -100.0) { chr = -99.8; } - if(alg != 2) { - Ciecam02::curvecolor(chr, Cp , sres, parsat); + if (alg != 2) { + Ciecam02::curvecolor (chr, Cp , sres, parsat); } else { - Ciecam02::curvecolor(0.0, Cp , sres, parsat); //chroma + Ciecam02::curvecolor (0.0, Cp , sres, parsat); //chroma } dred = 55.f; protect_red = 30.0f; sk = 1; - Color::skinred(Jpro, hpro, sres, Cp, dred, protect_red, sk, rstprotection, ko, Cpro); + Color::skinred (Jpro, hpro, sres, Cp, dred, protect_red, sk, rstprotection, ko, Cpro); - if(Jpro < 1. && Cpro > 12.) { + if (Jpro < 1. && Cpro > 12.) { Cpro = 12.; //reduce artifacts by "pseudo gamut control CIECAM" - } else if(Jpro < 2. && Cpro > 15.) { + } else if (Jpro < 2. && Cpro > 15.) { Cpro = 15.; - } else if(Jpro < 4. && Cpro > 30.) { + } else if (Jpro < 4. && Cpro > 30.) { Cpro = 30.; - } else if(Jpro < 7. && Cpro > 50.) { + } else if (Jpro < 7. && Cpro > 50.) { Cpro = 50.; } hpro = hpro + hue; - if( hpro < 0.0 ) { + if ( hpro < 0.0 ) { hpro += 360.0; //hue } } @@ -762,28 +770,28 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh float Jold100 = (float) Jpro; float redu = 25.f; float reduc = 1.f; - const Lightcurve& userColCurveJ1 = static_cast<const Lightcurve&>(customColCurve1); - userColCurveJ1.Apply(Jj); + const Lightcurve& userColCurveJ1 = static_cast<const Lightcurve&> (customColCurve1); + userColCurveJ1.Apply (Jj); - if(Jj > Jold) { - if(Jj < 65535.f) { - if(Jold < 327.68f * redu) { + if (Jj > Jold) { + if (Jj < 65535.f) { + if (Jold < 327.68f * redu) { Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility } else { - reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM ((100.f - Jold100) / (100.f - redu), 0.f, 1.f); Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } } - } else if(Jj > 10.f) { + } else if (Jj > 10.f) { Jj = 0.8f * (Jj - Jold) + Jold; } else if (Jj >= 0.f) { Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts } - Jpro = (double)(Jj / 327.68f); + Jpro = (double) (Jj / 327.68f); - if(Jpro < 1.) { + if (Jpro < 1.) { Jpro = 1.; } @@ -798,29 +806,29 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh float redu = 20.f; float reduc = 1.f; - const Brightcurve& userColCurveB1 = static_cast<const Brightcurve&>(customColCurve1); - userColCurveB1.Apply(Qq); + const Brightcurve& userColCurveB1 = static_cast<const Brightcurve&> (customColCurve1); + userColCurveB1.Apply (Qq); - if(Qq > Qold) { - if(Qq < 65535.f) { - if(Qold < 327.68f * redu) { + if (Qq > Qold) { + if (Qq < 65535.f) { + if (Qold < 327.68f * redu) { Qq = 0.25f * (Qq - Qold) + Qold; //divide sensibility } else { - reduc = LIM((100.f - Qold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM ((100.f - Qold100) / (100.f - redu), 0.f, 1.f); Qq = 0.25f * reduc * (Qq - Qold) + Qold; //reduct sensibility in highlights } } - } else if(Qq > 10.f) { + } else if (Qq > 10.f) { Qq = 0.5f * (Qq - Qold) + Qold; } else if (Qq >= 0.f) { Qq = 0.7f * (Qq - Qold) + Qold; // not zero ==>artifacts } - Qpro = (double)(Qq * (coef) / 327.68f); - Jpro = 100.*(Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0)); + Qpro = (double) (Qq * (coef) / 327.68f); + Jpro = 100.* (Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0)); t1B = true; - if(Jpro < 1.) { + if (Jpro < 1.) { Jpro = 1.; } @@ -839,35 +847,35 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh float Jold100 = (float) Jpro; float redu = 25.f; float reduc = 1.f; - const Lightcurve& userColCurveJ2 = static_cast<const Lightcurve&>(customColCurve2); - userColCurveJ2.Apply(Jj); + const Lightcurve& userColCurveJ2 = static_cast<const Lightcurve&> (customColCurve2); + userColCurveJ2.Apply (Jj); - if(Jj > Jold) { - if(Jj < 65535.f) { - if(Jold < 327.68f * redu) { + if (Jj > Jold) { + if (Jj < 65535.f) { + if (Jold < 327.68f * redu) { Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility } else { - reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM ((100.f - Jold100) / (100.f - redu), 0.f, 1.f); Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } } - } else if(Jj > 10.f) { - if(!t1L) { + } else if (Jj > 10.f) { + if (!t1L) { Jj = 0.8f * (Jj - Jold) + Jold; } else { Jj = 0.4f * (Jj - Jold) + Jold; } } else if (Jj >= 0.f) { - if(!t1L) { + if (!t1L) { Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts } else { Jj = 0.5f * (Jj - Jold) + Jold; } } - Jpro = (double)(Jj / 327.68f); + Jpro = (double) (Jj / 327.68f); - if(Jpro < 1.) { + if (Jpro < 1.) { Jpro = 1.; } @@ -880,40 +888,40 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh float redu = 20.f; float reduc = 1.f; - const Brightcurve& userColCurveB2 = static_cast<const Brightcurve&>(customColCurve2); - userColCurveB2.Apply(Qq); + const Brightcurve& userColCurveB2 = static_cast<const Brightcurve&> (customColCurve2); + userColCurveB2.Apply (Qq); - if(Qq > Qold) { - if(Qq < 65535.f) { - if(Qold < 327.68f * redu) { + if (Qq > Qold) { + if (Qq < 65535.f) { + if (Qold < 327.68f * redu) { Qq = 0.25f * (Qq - Qold) + Qold; //divide sensibility } else { - reduc = LIM((100.f - Qold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM ((100.f - Qold100) / (100.f - redu), 0.f, 1.f); Qq = 0.25f * reduc * (Qq - Qold) + Qold; //reduct sensibility in highlights } } - } else if(Qq > 10.f) { + } else if (Qq > 10.f) { Qq = 0.5f * (Qq - Qold) + Qold; } else if (Qq >= 0.f) { Qq = 0.7f * (Qq - Qold) + Qold; // not zero ==>artifacts } - Qpro = (double)(Qq * (coef) / 327.68f); - Jpro = 100.*(Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0)); + Qpro = (double) (Qq * (coef) / 327.68f); + Jpro = 100.* (Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0)); t2B = true; - if(t1L) { //to workaround the problem if we modify curve1-lightnees after curve2 brightness(the cat that bites its own tail!) in fact it's another type of curve only for this case + if (t1L) { //to workaround the problem if we modify curve1-lightnees after curve2 brightness(the cat that bites its own tail!) in fact it's another type of curve only for this case coef = 2.f; //adapt Q to J approximation Qq = (float) Qpro * coef; Qold = Qq; - const Lightcurve& userColCurveJ1 = static_cast<const Lightcurve&>(customColCurve1); - userColCurveJ1.Apply(Qq); + const Lightcurve& userColCurveJ1 = static_cast<const Lightcurve&> (customColCurve1); + userColCurveJ1.Apply (Qq); Qq = 0.1f * (Qq - Qold) + Qold; //approximative adaptation - Qpro = (double)(Qq / coef); - Jpro = 100.*(Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0)); + Qpro = (double) (Qq / coef); + Jpro = 100.* (Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0)); } - if(Jpro < 1.) { + if (Jpro < 1.) { Jpro = 1.; } } @@ -925,21 +933,21 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh double coef = 327.68 / parsat; float Cc = (float) Cpro * coef; float Ccold = Cc; - const Chromacurve& userColCurve = static_cast<const Chromacurve&>(customColCurve3); - userColCurve.Apply(Cc); + const Chromacurve& userColCurve = static_cast<const Chromacurve&> (customColCurve3); + userColCurve.Apply (Cc); float dred = 55.f; float protect_red = 30.0f; float sk = 1; float ko = 1.f / coef; - Color::skinred(Jpro, hpro, Cc, Ccold, dred, protect_red, sk, rstprotection, ko, Cpro); + Color::skinred (Jpro, hpro, Cc, Ccold, dred, protect_red, sk, rstprotection, ko, Cpro); - if(Jpro < 1. && Cpro > 12.) { + if (Jpro < 1. && Cpro > 12.) { Cpro = 12.; //reduce artifacts by "pseudo gamut control CIECAM" - } else if(Jpro < 2. && Cpro > 15.) { + } else if (Jpro < 2. && Cpro > 15.) { Cpro = 15.; - } else if(Jpro < 4. && Cpro > 30.) { + } else if (Jpro < 4. && Cpro > 30.) { Cpro = 30.; - } else if(Jpro < 7. && Cpro > 50.) { + } else if (Jpro < 7. && Cpro > 50.) { Cpro = 50.; } @@ -949,18 +957,18 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh double coef = 327.68 / parsat; float Ss = (float) spro * coef; float Sold = Ss; - const Saturcurve& userColCurve = static_cast<const Saturcurve&>(customColCurve3); - userColCurve.Apply(Ss); + const Saturcurve& userColCurve = static_cast<const Saturcurve&> (customColCurve3); + userColCurve.Apply (Ss); Ss = 0.6f * (Ss - Sold) + Sold; //divide sensibility saturation - double coe = pow(fl, 0.25); + double coe = pow (fl, 0.25); float dred = 100.f; // in C mode float protect_red = 80.0f; // in C mode - dred = 100.0 * sqrt((dred * coe) / Qpro); - protect_red = 100.0 * sqrt((protect_red * coe) / Qpro); + dred = 100.0 * sqrt ((dred * coe) / Qpro); + protect_red = 100.0 * sqrt ((protect_red * coe) / Qpro); int sk = 0; float ko = 1.f / coef; - Color::skinred(Jpro, hpro, Ss, Sold, dred, protect_red, sk, rstprotection, ko, spro); - Qpro = ( 4.0 / c ) * sqrt( Jpro / 100.0 ) * ( aw + 4.0 ) ; + Color::skinred (Jpro, hpro, Ss, Sold, dred, protect_red, sk, rstprotection, ko, spro); + Qpro = ( 4.0 / c ) * sqrt ( Jpro / 100.0 ) * ( aw + 4.0 ) ; Cpro = (spro * spro * Qpro) / (10000.0); c1s = 1; @@ -969,25 +977,25 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh double coef = 327.68 / parsat; float Mm = (float) Mpro * coef; float Mold = Mm; - const Colorfcurve& userColCurve = static_cast<const Colorfcurve&>(customColCurve3); - userColCurve.Apply(Mm); - double coe = pow(fl, 0.25); + const Colorfcurve& userColCurve = static_cast<const Colorfcurve&> (customColCurve3); + userColCurve.Apply (Mm); + double coe = pow (fl, 0.25); float dred = 100.f; //in C mode float protect_red = 80.0f; // in C mode dred *= coe; //in M mode protect_red *= coe; int sk = 0; float ko = 1.f / coef; - Color::skinred(Jpro, hpro, Mm, Mold, dred, protect_red, sk, rstprotection, ko, Mpro); + Color::skinred (Jpro, hpro, Mm, Mold, dred, protect_red, sk, rstprotection, ko, Mpro); Cpro = Mpro / coe; - if(Jpro < 1. && Mpro > 12.*coe) { + if (Jpro < 1. && Mpro > 12.*coe) { Mpro = 12.*coe; //reduce artifacts by "pseudo gamut control CIECAM" - } else if(Jpro < 2. && Mpro > 15.*coe) { + } else if (Jpro < 2. && Mpro > 15.*coe) { Mpro = 15.*coe; - } else if(Jpro < 4. && Mpro > 30.*coe) { + } else if (Jpro < 4. && Mpro > 30.*coe) { Mpro = 30.*coe; - } else if(Jpro < 7. && Mpro > 50.*coe) { + } else if (Jpro < 7. && Mpro > 50.*coe) { Mpro = 50.*coe; } @@ -997,17 +1005,17 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh } //to retrieve the correct values of variables - if(t2B && t1B) { + if (t2B && t1B) { Jpro = (100.0 * Qpro * Qpro) / (wh * wh); // for brightness curve } - if(c1s == 1) { - Qpro = ( 4.0 / c ) * sqrt( Jpro / 100.0 ) * ( aw + 4.0 ) ; //for saturation curve + if (c1s == 1) { + Qpro = ( 4.0 / c ) * sqrt ( Jpro / 100.0 ) * ( aw + 4.0 ) ; //for saturation curve Cpro = (spro * spro * Qpro) / (10000.0); } - if(c1co == 1) { - double coe = pow(fl, 0.25); // for colorfullness curve + if (c1co == 1) { + double coe = pow (fl, 0.25); // for colorfullness curve Cpro = Mpro / coe; } @@ -1019,7 +1027,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh h = hpro; s = spro; - if(params->colorappearance.tonecie || settings->autocielab) { //use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail + if (params->colorappearance.tonecie || settings->autocielab) { //use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail // if(params->colorappearance.tonecie || params->colorappearance.sharpcie){//use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail float Qred = ( 4.0 / c) * ( aw + 4.0 ); //estimate Q max if J=100.0 ncie->Q_p[i][j] = (float)Q + epsil; //epsil to avoid Q=0 @@ -1028,19 +1036,19 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh ncie->h_p[i][j] = (float)h; ncie->C_p[i][j] = (float)C + epsil; // ncie->s_p[i][j]=(float)s; - ncie->sh_p[i][j] = (float) 32768.*(( 4.0 / c ) * sqrt( J / 100.0 ) * ( aw + 4.0 )) / Qred ; + ncie->sh_p[i][j] = (float) 32768.* (( 4.0 / c ) * sqrt ( J / 100.0 ) * ( aw + 4.0 )) / Qred ; // ncie->ch_p[i][j]=(float) 327.68*C; - if(ncie->Q_p[i][j] < minQ) { + if (ncie->Q_p[i][j] < minQ) { minQ = ncie->Q_p[i][j]; //minima } - if(ncie->Q_p[i][j] > maxQ) { + if (ncie->Q_p[i][j] > maxQ) { maxQ = ncie->Q_p[i][j]; //maxima } } - if(!params->colorappearance.tonecie || !settings->autocielab || !params->epd.enabled ) { + if (!params->colorappearance.tonecie || !settings->autocielab || !params->epd.enabled ) { // if(!params->epd.enabled || !params->colorappearance.tonecie || !settings->autocielab){ // if(!params->epd.enabled || !params->colorappearance.tonecie || !params->colorappearance.sharpcie){ @@ -1049,10 +1057,10 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh int libr = 0; int colch = 0; - if(curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { + if (curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { brli = 70.0; libr = 1; - } else if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT) { + } else if (curveMode == ColorAppearanceParams::TC_MODE_LIGHT) { brli = 327.; libr = 0; } @@ -1060,25 +1068,26 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { chsacol = 327.; colch = 0; - } else if(curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { + } else if (curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0; colch = 1; - } else if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { + } else if (curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { chsacol = 327.0; colch = 2; } - if(ciedata) { + if (ciedata) { // Data for J Q M s and C histograms //update histogram jp = true; - if(pW != 1) { //only with improccoordinator + 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)*/ { - posl = CLIP((int)(J * brli)); //327 for J + + if (libr == 1) { + posl = CLIP ((int) (Q * brli)); //40.0 to 100.0 approximative factor for Q - 327 for J + } else { /*if(libr == 0)*/ + posl = CLIP ((int) (J * brli)); //327 for J } hist16JCAM[posl]++; @@ -1086,14 +1095,15 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh chropC = true; - if(pW != 1) { //only with improccoordinator + 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)*/ { - posc = CLIP((int)(M * chsacol)); + + 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)*/ + posc = CLIP ((int) (M * chsacol)); } hist16_CCAM[posc]++; @@ -1103,42 +1113,42 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh double xx, yy, zz; //double nj, nbbj, ncbj, flj, czj, dj, awj; //process normal==> viewing - Ciecam02::jch2xyz_ciecam02( xx, yy, zz, - J, C, h, - xw2, yw2, zw2, - yb2, la2, - f2, c2, nc2, gamu, nj, nbbj, ncbj, flj, czj, dj, awj); + Ciecam02::jch2xyz_ciecam02 ( xx, yy, zz, + J, C, h, + xw2, yw2, zw2, + yb2, la2, + f2, c2, nc2, gamu, nj, nbbj, ncbj, flj, czj, dj, awj); x = (float)xx * 655.35; y = (float)yy * 655.35; z = (float)zz * 655.35; float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab(x, y, z, Ll, aa, bb); + Color::XYZ2Lab (x, y, z, Ll, aa, bb); lab->L[i][j] = Ll; lab->a[i][j] = aa; lab->b[i][j] = bb; // gamut control in Lab mode; I must study how to do with cIECAM only - if(gamu == 1) { + if (gamu == 1) { float R, G, B; float HH, Lprov1, Chprov1; Lprov1 = lab->L[i][j] / 327.68f; - Chprov1 = sqrt(SQR(lab->a[i][j] / 327.68f) + SQR(lab->b[i][j] / 327.68f)); - HH = atan2(lab->b[i][j], lab->a[i][j]); + Chprov1 = sqrt (SQR (lab->a[i][j] / 327.68f) + SQR (lab->b[i][j] / 327.68f)); + HH = atan2 (lab->b[i][j], lab->a[i][j]); #ifdef _DEBUG bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (HH, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly (HH, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; - lab->a[i][j] = 327.68f * Chprov1 * cos(HH); - lab->b[i][j] = 327.68f * Chprov1 * sin(HH); + lab->a[i][j] = 327.68f * Chprov1 * cos (HH); + lab->b[i][j] = 327.68f * Chprov1 * sin (HH); } } @@ -1146,26 +1156,26 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh } // End of parallelization - if(!params->epd.enabled || !params->colorappearance.tonecie || !settings->autocielab) { //normal + if (!params->epd.enabled || !params->colorappearance.tonecie || !settings->autocielab) { //normal //if(!params->epd.enabled || !params->colorappearance.tonecie || !params->colorappearance.sharpcie){//normal - if(ciedata) { + if (ciedata) { //update histogram J - if(pW != 1) { //only with improccoordinator + if (pW != 1) { //only with improccoordinator for (int i = 0; i < 32768; i++) { // if (jp) { float hval = dLcurve[i]; - int hi = (int)(255.0 * CLIPD(hval)); // + int hi = (int) (255.0 * CLIPD (hval)); // histLCAM[hi] += hist16JCAM[i] ; } } } - if(pW != 1) { //only with improccoordinator + if (pW != 1) { //only with improccoordinator for (int i = 0; i < 48000; i++) { // if (chropC) { float hvalc = dCcurve[i]; - int hic = (int)(255.0 * CLIPD(hvalc)); // + int hic = (int) (255.0 * CLIPD (hvalc)); // histCCAM[hic] += hist16_CCAM[i] ; } } @@ -1177,35 +1187,35 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh if (settings->verbose) { t2e.set(); - printf("CIECAM02 performed in %d usec:\n", t2e.etime(t1e)); + printf ("CIECAM02 performed in %d usec:\n", t2e.etime (t1e)); // printf("minc=%f maxc=%f minj=%f maxj=%f\n",minc,maxc,minj,maxj); } #endif - if(settings->autocielab) { + if (settings->autocielab) { //if(params->colorappearance.sharpcie) { //all this treatments reduce artifacts, but can lead to slightly different results - if(params->defringe.enabled) if(execsharp) { + if (params->defringe.enabled) if (execsharp) { ImProcFunctions::defringecam (ncie); // } //if(params->dirpyrequalizer.enabled) if(execsharp) { - if(params->dirpyrequalizer.enabled) { - if(params->dirpyrequalizer.gamutlab /*&& execsharp*/) { - float b_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[0]) / 100.0f; - float t_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[1]) / 100.0f; - float b_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[2]) / 100.0f; - float t_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[3]) / 100.0f; + if (params->dirpyrequalizer.enabled) { + if (params->dirpyrequalizer.gamutlab /*&& execsharp*/) { + float b_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[0]) / 100.0f; + float t_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[1]) / 100.0f; + float b_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[2]) / 100.0f; + float t_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[3]) / 100.0f; float artifact = (float) settings->artifact_cbdl; - if(artifact > 6.f) { + if (artifact > 6.f) { artifact = 6.f; } - if(artifact < 0.f) { + if (artifact < 0.f) { artifact = 1.f; } @@ -1217,38 +1227,38 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh } } - if(params->colorappearance.badpixsl > 0) if(execsharp) { + if (params->colorappearance.badpixsl > 0) if (execsharp) { int mode = params->colorappearance.badpixsl; ImProcFunctions::badpixcam (ncie, 3.4, 5, mode, 0, 0, 0, 0, 0, 0, 1);//for bad pixels CIECAM } - if (params->sharpenMicro.enabled)if(execsharp) { - ImProcFunctions::MLmicrocontrastcam(ncie); + if (params->sharpenMicro.enabled)if (execsharp) { + ImProcFunctions::MLmicrocontrastcam (ncie); } - if(params->sharpening.enabled) - if(execsharp) { + if (params->sharpening.enabled) + if (execsharp) { float **buffer = lab->L; // We can use the L-buffer from lab as buffer to save some memory ImProcFunctions::sharpeningcam (ncie, buffer); // sharpening adapted to CIECAM } //if(params->dirpyrequalizer.enabled) if(execsharp) { - if(params->dirpyrequalizer.enabled /*&& (execsharp)*/) { + if (params->dirpyrequalizer.enabled /*&& (execsharp)*/) { // if (params->dirpyrequalizer.algo=="FI") choice=0; // else if(params->dirpyrequalizer.algo=="LA") choice=1; - if(rtt == 1) { - float b_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[0]) / 100.0f; - float t_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[1]) / 100.0f; - float b_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[2]) / 100.0f; - float t_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[3]) / 100.0f; + if (rtt == 1) { + float b_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[0]) / 100.0f; + float t_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[1]) / 100.0f; + float b_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[2]) / 100.0f; + float t_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[3]) / 100.0f; int choice = 0; //not disabled in case of ! always 0 - dirpyr_equalizercam(ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, ncie->h_p, ncie->C_p, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, true, params->dirpyrequalizer.gamutlab, b_l, t_l, t_r, b_r, choice, scalecd); //contrast by detail adapted to CIECAM + dirpyr_equalizercam (ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, ncie->h_p, ncie->C_p, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, true, params->dirpyrequalizer.gamutlab, b_l, t_l, t_r, b_r, choice, scalecd); //contrast by detail adapted to CIECAM } } float Qredi = ( 4.0 / c_) * ( a_w + 4.0 ); - float co_e = (pow(f_l, 0.25f)); + float co_e = (pow (f_l, 0.25f)); #ifndef _DEBUG #pragma omp parallel default(shared) firstprivate(height,width, Qredi,a_w,c_) @@ -1262,18 +1272,18 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh for (int j = 0; j < width; j++) { float interm = Qredi * ncie->sh_p[i][j] / (32768.f); ncie->J_p[i][j] = 100.0 * interm * interm / ((a_w + 4.) * (a_w + 4.) * (4. / c_) * (4. / c_)); - ncie->Q_p[i][j] = ( 4.0 / c_) * ( a_w + 4.0 ) * sqrt(ncie->J_p[i][j] / 100.f); + ncie->Q_p[i][j] = ( 4.0 / c_) * ( a_w + 4.0 ) * sqrt (ncie->J_p[i][j] / 100.f); ncie->M_p[i][j] = ncie->C_p[i][j] * co_e; } } } - if((params->colorappearance.tonecie || (params->colorappearance.tonecie && params->epd.enabled)) || (params->sharpening.enabled && settings->autocielab) + if ((params->colorappearance.tonecie || (params->colorappearance.tonecie && params->epd.enabled)) || (params->sharpening.enabled && settings->autocielab) || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)) { - if(params->epd.enabled && params->colorappearance.tonecie && algepd) { - ImProcFunctions::EPDToneMapCIE(ncie, a_w, c_, w_h, width, height, begh, endh, minQ, maxQ, Iterates, scale ); + if (params->epd.enabled && params->colorappearance.tonecie && algepd) { + ImProcFunctions::EPDToneMapCIE (ncie, a_w, c_, w_h, width, height, begh, endh, minQ, maxQ, Iterates, scale ); } //EPDToneMapCIE adapted to CIECAM @@ -1302,11 +1312,11 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh double xx, yy, zz; float x, y, z; const float eps = 0.0001; - float co_e = (pow(f_l, 0.25f)) + eps; + float co_e = (pow (f_l, 0.25f)) + eps; // if(params->epd.enabled) ncie->J_p[i][j]=(100.0* ncie->Q_p[i][j]*ncie->Q_p[i][j])/(w_h*w_h); - if(params->epd.enabled) { - ncie->J_p[i][j] = (100.0 * ncie->Q_p[i][j] * ncie->Q_p[i][j]) / SQR((4. / c) * (aw + 4.)); + if (params->epd.enabled) { + ncie->J_p[i][j] = (100.0 * ncie->Q_p[i][j] * ncie->Q_p[i][j]) / SQR ((4. / c) * (aw + 4.)); } ncie->C_p[i][j] = (ncie->M_p[i][j]) / co_e; @@ -1316,10 +1326,10 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh int libr = 0; int colch = 0; - if(curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { + if (curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { brli = 70.0; libr = 1; - } else if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT) { + } else if (curveMode == ColorAppearanceParams::TC_MODE_LIGHT) { brli = 327.; libr = 0; } @@ -1327,25 +1337,26 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { chsacol = 327.; colch = 0; - } else if(curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { + } else if (curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0; colch = 1; - } else if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { + } else if (curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { chsacol = 327.0; colch = 2; } - if(ciedata) { + if (ciedata) { // Data for J Q M s and C histograms //update histogram jp = true; - if(pW != 1) { //only with improccoordinator + 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)*/ { - posl = CLIP((int)(ncie->J_p[i][j] * brli)); //327 for J + + 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)*/ + posl = CLIP ((int) (ncie->J_p[i][j] * brli)); //327 for J } hist16JCAM[posl]++; @@ -1353,15 +1364,16 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh chropC = true; - if(pW != 1) { //only with improccoordinator + 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) { - float 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)*/ { - posc = CLIP((int)(ncie->M_p[i][j] * chsacol)); + + 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) { + float 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)*/ + posc = CLIP ((int) (ncie->M_p[i][j] * chsacol)); } hist16_CCAM[posc]++; @@ -1370,41 +1382,41 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh //end histograms // double nd, nbbd, ncbd, fld, czd, dd, awd; - Ciecam02::jch2xyz_ciecam02( xx, yy, zz, - ncie->J_p[i][j], ncie->C_p[i][j], ncie->h_p[i][j], - xw2, yw2, zw2, - yb2, la2, - f2, c2, nc2, gamu, nj, nbbj, ncbj, flj, czj, dj, awj); + Ciecam02::jch2xyz_ciecam02 ( xx, yy, zz, + ncie->J_p[i][j], ncie->C_p[i][j], ncie->h_p[i][j], + xw2, yw2, zw2, + yb2, la2, + f2, c2, nc2, gamu, nj, nbbj, ncbj, flj, czj, dj, awj); x = (float)xx * 655.35; y = (float)yy * 655.35; z = (float)zz * 655.35; float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab(x, y, z, Ll, aa, bb); + Color::XYZ2Lab (x, y, z, Ll, aa, bb); lab->L[i][j] = Ll; lab->a[i][j] = aa; lab->b[i][j] = bb; - if(gamu == 1) { + if (gamu == 1) { float R, G, B; float HH, Lprov1, Chprov1; Lprov1 = lab->L[i][j] / 327.68f; - Chprov1 = sqrt(SQR(lab->a[i][j] / 327.68f) + SQR(lab->b[i][j] / 327.68f)); - HH = atan2(lab->b[i][j], lab->a[i][j]); + Chprov1 = sqrt (SQR (lab->a[i][j] / 327.68f) + SQR (lab->b[i][j] / 327.68f)); + HH = atan2 (lab->b[i][j], lab->a[i][j]); #ifdef _DEBUG bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, Lprov1, Chprov1, R, G, B, wipa, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (HH, Lprov1, Chprov1, R, G, B, wipa, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, Lprov1, Chprov1, R, G, B, wipa, highlight, 0.15f, 0.96f); + Color::gamutLchonly (HH, Lprov1, Chprov1, R, G, B, wipa, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; - lab->a[i][j] = 327.68f * Chprov1 * cos(HH); - lab->b[i][j] = 327.68f * Chprov1 * sin(HH); + lab->a[i][j] = 327.68f * Chprov1 * cos (HH); + lab->b[i][j] = 327.68f * Chprov1 * sin (HH); } } @@ -1413,24 +1425,24 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh //end parallelization //show CIECAM histograms - if(ciedata) { + if (ciedata) { //update histogram J and Q - if(pW != 1) { //only with improccoordinator + if (pW != 1) { //only with improccoordinator for (int i = 0; i < 32768; i++) { // if (jp) { float hval = dLcurve[i]; - int hi = (int)(255.0 * CLIPD(hval)); // + int hi = (int) (255.0 * CLIPD (hval)); // histLCAM[hi] += hist16JCAM[i] ; } } } //update color histogram M,s,C - if(pW != 1) { //only with improccoordinator + if (pW != 1) { //only with improccoordinator for (int i = 0; i < 48000; i++) { // if (chropC) { float hvalc = dCcurve[i]; - int hic = (int)(255.0 * CLIPD(hvalc)); // + int hic = (int) (255.0 * CLIPD (hvalc)); // histCCAM[hic] += hist16_CCAM[i] ; } } @@ -1449,7 +1461,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2, const ColorAppearance & customColCurve3, LUTu & histLCAM, LUTu & histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, bool execsharp, float &d, int scalecd, int rtt) { - if(params->colorappearance.enabled) { + if (params->colorappearance.enabled) { #ifdef _DEBUG MyTime t1e, t2e; @@ -1460,10 +1472,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int LUTu hist16JCAM; LUTu hist16_CCAM; - if(pW != 1 && params->colorappearance.datacie) { //only with improccoordinator - hist16JCAM(32768); + if (pW != 1 && params->colorappearance.datacie) { //only with improccoordinator + hist16JCAM (32768); hist16JCAM.clear(); - hist16_CCAM(48000); + hist16_CCAM (48000); hist16_CCAM.clear(); } @@ -1481,29 +1493,29 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int bool algepd = false; const bool epdEnabled = params->epd.enabled; - bool ciedata = (params->colorappearance.datacie && pW != 1) && !((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) + bool ciedata = (params->colorappearance.datacie && pW != 1) && ! ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); ColorTemp::temp2mulxyz (params->wb.temperature, params->wb.green, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB //viewing condition for surround - if(params->colorappearance.surround == "Average") { + if (params->colorappearance.surround == "Average") { f = 1.00f; c = 0.69f; nc = 1.00f; f2 = 1.0f, c2 = 0.69f, nc2 = 1.0f; - } else if(params->colorappearance.surround == "Dim") { + } else if (params->colorappearance.surround == "Dim") { f2 = 0.9f; c2 = 0.59f; nc2 = 0.9f; f = 1.0f, c = 0.69f, nc = 1.0f; - } else if(params->colorappearance.surround == "Dark") { + } else if (params->colorappearance.surround == "Dark") { f2 = 0.8f; c2 = 0.525f; nc2 = 0.8f; f = 1.0f, c = 0.69f, nc = 1.0f; - } else if(params->colorappearance.surround == "ExtremelyDark") { + } else if (params->colorappearance.surround == "ExtremelyDark") { f2 = 0.8f; c2 = 0.41f; nc2 = 0.8f; @@ -1511,7 +1523,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } //scene condition for surround - if(params->colorappearance.surrsource) { + if (params->colorappearance.surrsource) { f = 0.85f; // if user => source image has surround very dark c = 0.55f; nc = 0.85f; @@ -1520,9 +1532,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //with which algorithm if (params->colorappearance.algo == "JC") { alg = 0; - } else if(params->colorappearance.algo == "JS") { + } else if (params->colorappearance.algo == "JS") { alg = 1; - } else if(params->colorappearance.algo == "QM") { + } else if (params->colorappearance.algo == "QM") { alg = 2; algepd = true; } else { /*if(params->colorappearance.algo == "ALL")*/ @@ -1531,31 +1543,31 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } //settings white point of output device - or illuminant viewing - if(settings->viewingdevice == 0) { + if (settings->viewingdevice == 0) { xwd = 96.42f; //5000K ywd = 100.0f; zwd = 82.52f; - } else if(settings->viewingdevice == 1) { + } else if (settings->viewingdevice == 1) { xwd = 95.68f; //5500 ywd = 100.0f; zwd = 92.15f; - } else if(settings->viewingdevice == 2) { + } else if (settings->viewingdevice == 2) { xwd = 95.24f; //6000 ywd = 100.0f; zwd = 100.81f; - } else if(settings->viewingdevice == 3) { + } else if (settings->viewingdevice == 3) { xwd = 95.04f; //6500 ywd = 100.0f; zwd = 108.88f; - } else if(settings->viewingdevice == 4) { + } else if (settings->viewingdevice == 4) { xwd = 109.85f; //tungsten ywd = 100.0f; zwd = 35.58f; - } else if(settings->viewingdevice == 5) { + } else if (settings->viewingdevice == 5) { xwd = 99.18f; //fluo F2 ywd = 100.0f; zwd = 67.39f; - } else if(settings->viewingdevice == 6) { + } else if (settings->viewingdevice == 6) { xwd = 95.04f; //fluo F7 ywd = 100.0f; zwd = 108.75f; @@ -1567,32 +1579,36 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //settings mean Luminance Y of output device or viewing - if(settings->viewingdevicegrey == 0) { + if (settings->viewingdevicegrey == 0) { yb2 = 5.0f; - } else if(settings->viewingdevicegrey == 1) { + } else if (settings->viewingdevicegrey == 1) { yb2 = 10.0f; - } else if(settings->viewingdevicegrey == 2) { + } else if (settings->viewingdevicegrey == 2) { yb2 = 15.0f; - } else if(settings->viewingdevicegrey == 3) { + } else if (settings->viewingdevicegrey == 3) { yb2 = 18.0f; - } else if(settings->viewingdevicegrey == 4) { + } else if (settings->viewingdevicegrey == 4) { yb2 = 23.0f; - } else if(settings->viewingdevicegrey == 5) { + } else if (settings->viewingdevicegrey == 5) { yb2 = 30.0f; } else { /* if(settings->viewingdevicegrey == 6)*/ yb2 = 40.0f; } //La and la2 = ambiant luminosity scene and viewing - la = float(params->colorappearance.adapscen); + la = float (params->colorappearance.adapscen); - if(pwb == 2) { - if(params->colorappearance.autoadapscen) { + if (pwb == 2) { + if (params->colorappearance.autoadapscen) { la = adap; } } - const float la2 = float(params->colorappearance.adaplum); + if (alg >= 2 && la < 200.f) { + la = 200.f; + } + + const float la2 = float (params->colorappearance.adaplum); // level of adaptation const float deg = (params->colorappearance.degree) / 100.0f; @@ -1601,33 +1617,33 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //algoritm's params float chr = 0.f; - if(alg == 0 || alg == 3) { + if (alg == 0 || alg == 3) { chr = params->colorappearance.chroma; - if(chr == -100.0f) { + if (chr == -100.0f) { chr = -99.8f; } } float schr = 0.f; - if(alg == 3 || alg == 1) { + if (alg == 3 || alg == 1) { schr = params->colorappearance.schroma; - if(schr > 0.0) { + if (schr > 0.0) { schr = schr / 2.0f; //divide sensibility for saturation } - if(alg == 3) { - if(schr == -100.0f) { + if (alg == 3) { + if (schr == -100.0f) { schr = -99.f; } - if(schr == 100.0f) { + if (schr == 100.0f) { schr = 98.f; } } else { - if(schr == -100.0f) { + if (schr == -100.0f) { schr = -99.8f; } } @@ -1635,14 +1651,14 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float mchr = 0.f; - if(alg == 3 || alg == 2) { + if (alg == 3 || alg == 2) { mchr = params->colorappearance.mchroma; - if(mchr == -100.0f) { + if (mchr == -100.0f) { mchr = -99.8f ; } - if(mchr == 100.0f) { + if (mchr == 100.0f) { mchr = 99.9f; } } @@ -1652,21 +1668,21 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int // extracting datas from 'params' to avoid cache flush (to be confirmed) const ColorAppearanceParams::eTCModeId curveMode = params->colorappearance.curveMode; - const bool hasColCurve1 = bool(customColCurve1); + const bool hasColCurve1 = bool (customColCurve1); const bool t1L = hasColCurve1 && curveMode == ColorAppearanceParams::TC_MODE_LIGHT; const ColorAppearanceParams::eTCModeId curveMode2 = params->colorappearance.curveMode2; - const bool hasColCurve2 = bool(customColCurve2); + const bool hasColCurve2 = bool (customColCurve2); const ColorAppearanceParams::eCTCModeId curveMode3 = params->colorappearance.curveMode3; - const bool hasColCurve3 = bool(customColCurve3); + const bool hasColCurve3 = bool (customColCurve3); bool needJ = (alg == 0 || alg == 1 || alg == 3); bool needQ = (alg == 2 || alg == 3); LUTu hist16J; LUTu hist16Q; - if((needJ && CAMBrightCurveJ.dirty) || (needQ && CAMBrightCurveQ.dirty) || (std::isnan(mean) && settings->viewinggreySc != 0)) { + if ((needJ && CAMBrightCurveJ.dirty) || (needQ && CAMBrightCurveQ.dirty) || (std::isnan (mean) && settings->viewinggreySc != 0)) { if (needJ) { hist16J (32768); @@ -1681,7 +1697,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float sum = 0.f; #ifdef _OPENMP - const int numThreads = min(max(width * height / 65536, 1), omp_get_max_threads()); + const int numThreads = min (max (width * height / 65536, 1), omp_get_max_threads()); #pragma omp parallel num_threads(numThreads) if(numThreads>1) #endif { @@ -1689,12 +1705,12 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int LUTu hist16Qthr; if (needJ) { - hist16Jthr(hist16J.getSize()); + hist16Jthr (hist16J.getSize()); hist16Jthr.clear(); } if (needQ) { - hist16Qthr(hist16Q.getSize()); + hist16Qthr (hist16Q.getSize()); hist16Qthr.clear(); } @@ -1705,10 +1721,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float currL = lab->L[i][j] / 327.68f; float koef; //rough correspondence between L and J - if(currL > 50.f) { - if(currL > 70.f) { - if(currL > 80.f) { - if(currL > 85.f) { + if (currL > 50.f) { + if (currL > 70.f) { + if (currL > 80.f) { + if (currL > 85.f) { koef = 0.97f; } else { koef = 0.93f; @@ -1724,9 +1740,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } } } else { - if(currL > 10.f) { - if(currL > 20.f) { - if(currL > 40.f) { + if (currL > 10.f) { + if (currL > 20.f) { + if (currL > 40.f) { koef = 0.75f; } else { koef = 0.7f; @@ -1740,11 +1756,11 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } if (needJ) { - hist16Jthr[(int)((koef * lab->L[i][j]))]++; //evaluate histogram luminance L # J + hist16Jthr[ (int) ((koef * lab->L[i][j]))]++; //evaluate histogram luminance L # J } if (needQ) { - hist16Qthr[(int) (sqrtf((koef * (lab->L[i][j])) * 32768.f))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L + hist16Qthr[ (int) (sqrtf ((koef * (lab->L[i][j])) * 32768.f))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L } sum += koef * lab->L[i][j]; //evaluate mean J to calculate Yb @@ -1752,17 +1768,17 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int #pragma omp critical { - if(needJ) { + if (needJ) { hist16J += hist16Jthr; } - if(needQ) { + if (needQ) { hist16Q += hist16Qthr; } } - if(std::isnan(mean)) { + if (std::isnan (mean)) { mean = (sum / ((height) * width)) / 327.68f; //for Yb for all image...if one day "pipette" we can adapt Yb for each zone } } @@ -1772,31 +1788,31 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //evaluate lightness, contrast } - if(settings->viewinggreySc == 0) { //auto + if (settings->viewinggreySc == 0) { //auto if (mean < 15.f) { yb = 3.0f; - } else if(mean < 30.f) { + } else if (mean < 30.f) { yb = 5.0f; - } else if(mean < 40.f) { + } else if (mean < 40.f) { yb = 10.0f; - } else if(mean < 45.f) { + } else if (mean < 45.f) { yb = 15.0f; - } else if(mean < 50.f) { + } else if (mean < 50.f) { yb = 18.0f; - } else if(mean < 55.f) { + } else if (mean < 55.f) { yb = 23.0f; - } else if(mean < 60.f) { + } else if (mean < 60.f) { yb = 30.0f; - } else if(mean < 70.f) { + } else if (mean < 70.f) { yb = 40.0f; - } else if(mean < 80.f) { + } else if (mean < 80.f) { yb = 60.0f; - } else if(mean < 90.f) { + } else if (mean < 90.f) { yb = 80.0f; } else { yb = 90.0f; } - } else if(settings->viewinggreySc == 1) { + } else if (settings->viewinggreySc == 1) { yb = 18.0f; //fixed } @@ -1809,14 +1825,14 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float xw1, yw1, zw1, xw2, yw2, zw2; // settings of WB: scene and viewing - if(params->colorappearance.wbmodel == "RawT") { + if (params->colorappearance.wbmodel == "RawT") { xw1 = 96.46f; //use RT WB; CAT 02 is used for output device (see prefreneces) yw1 = 100.0f; zw1 = 82.445f; 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; @@ -1826,12 +1842,12 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } float cz, wh, pfl; - Ciecam02::initcam1float(gamu, yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c); - const float pow1 = pow_F( 1.64f - pow_F( 0.29f, n ), 0.73f ); + Ciecam02::initcam1float (gamu, yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c); + const float pow1 = pow_F ( 1.64f - pow_F ( 0.29f, n ), 0.73f ); float nj, dj, nbbj, ncbj, czj, awj, flj; - Ciecam02::initcam2float(gamu, yb2, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj); + Ciecam02::initcam2float (gamu, yb2, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj); const float reccmcz = 1.f / (c2 * czj); - const float pow1n = pow_F( 1.64f - pow_F( 0.29f, nj ), 0.73f ); + const float pow1n = pow_F ( 1.64f - pow_F ( 0.29f, nj ), 0.73f ); const float epsil = 0.0001f; const float w_h = wh + epsil; @@ -1839,19 +1855,19 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int const float a_w = aw; const float c_ = c; const float f_l = fl; - const float coe = pow_F(fl, 0.25f); + const float coe = pow_F (fl, 0.25f); const float QproFactor = ( 0.4f / c ) * ( aw + 4.0f ) ; - const bool LabPassOne = !((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) - || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) - || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); + const bool LabPassOne = ! ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) + || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) + || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); if (needJ) { if (!CAMBrightCurveJ) { - CAMBrightCurveJ(32768, LUT_CLIP_ABOVE); + CAMBrightCurveJ (32768, LUT_CLIP_ABOVE); } - if(CAMBrightCurveJ.dirty) { + if (CAMBrightCurveJ.dirty) { Ciecam02::curveJfloat (params->colorappearance.jlight, params->colorappearance.contrast, hist16J, CAMBrightCurveJ);//lightness and contrast J CAMBrightCurveJ /= 327.68f; CAMBrightCurveJ.dirty = false; @@ -1860,10 +1876,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int if (needQ) { if (!CAMBrightCurveQ) { - CAMBrightCurveQ(32768, LUT_CLIP_ABOVE); + CAMBrightCurveQ (32768, LUT_CLIP_ABOVE); } - if(CAMBrightCurveQ.dirty) { + if (CAMBrightCurveQ.dirty) { Ciecam02::curveJfloat (params->colorappearance.qbright, params->colorappearance.qcontrast, hist16Q, CAMBrightCurveQ);//brightness and contrast Q CAMBrightCurveQ /= coefQ; CAMBrightCurveQ.dirty = false; @@ -1874,9 +1890,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //matrix for current working space TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); const float wip[3][3] = { - {(float)wiprof[0][0], (float)wiprof[0][1], (float)wiprof[0][2]}, - {(float)wiprof[1][0], (float)wiprof[1][1], (float)wiprof[1][2]}, - {(float)wiprof[2][0], (float)wiprof[2][1], (float)wiprof[2][2]} + { (float)wiprof[0][0], (float)wiprof[0][1], (float)wiprof[0][2]}, + { (float)wiprof[1][0], (float)wiprof[1][1], (float)wiprof[1][2]}, + { (float)wiprof[2][0], (float)wiprof[2][1], (float)wiprof[2][2]} }; #ifdef __SSE2__ @@ -1908,42 +1924,42 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int vfloat x, y, z; vfloat J, C, h, Q, M, s; - vfloat c655d35 = F2V(655.35f); + vfloat c655d35 = F2V (655.35f); - for(k = 0; k < width - 3; k += 4) { - Color::Lab2XYZ(LVFU(lab->L[i][k]), LVFU(lab->a[i][k]), LVFU(lab->b[i][k]), x, y, z); + for (k = 0; k < width - 3; k += 4) { + Color::Lab2XYZ (LVFU (lab->L[i][k]), LVFU (lab->a[i][k]), LVFU (lab->b[i][k]), x, y, z); x = x / c655d35; y = y / c655d35; z = z / c655d35; - Ciecam02::xyz2jchqms_ciecam02float( J, C, h, - Q, M, s, F2V(aw), F2V(fl), F2V(wh), - x, y, z, - F2V(xw1), F2V(yw1), F2V(zw1), - F2V(c), F2V(nc), F2V(pow1), F2V(nbb), F2V(ncb), F2V(pfl), F2V(cz), F2V(d)); - STVF(Jbuffer[k], J); - STVF(Cbuffer[k], C); - STVF(hbuffer[k], h); - STVF(Qbuffer[k], Q); - STVF(Mbuffer[k], M); - STVF(sbuffer[k], s); + Ciecam02::xyz2jchqms_ciecam02float ( J, C, h, + Q, M, s, F2V (aw), F2V (fl), F2V (wh), + x, y, z, + F2V (xw1), F2V (yw1), F2V (zw1), + F2V (c), F2V (nc), F2V (pow1), F2V (nbb), F2V (ncb), F2V (pfl), F2V (cz), F2V (d)); + STVF (Jbuffer[k], J); + STVF (Cbuffer[k], C); + STVF (hbuffer[k], h); + STVF (Qbuffer[k], Q); + STVF (Mbuffer[k], M); + STVF (sbuffer[k], s); } - for(; k < width; k++) { + for (; k < width; k++) { float L = lab->L[i][k]; float a = lab->a[i][k]; float b = lab->b[i][k]; float x, y, z; //convert Lab => XYZ - Color::Lab2XYZ(L, a, b, x, y, z); + Color::Lab2XYZ (L, a, b, x, y, z); x = x / 655.35f; y = y / 655.35f; z = z / 655.35f; float J, C, h, Q, M, s; - Ciecam02::xyz2jchqms_ciecam02float( J, C, h, - Q, M, s, aw, fl, wh, - x, y, z, - xw1, yw1, zw1, - c, nc, gamu, pow1, nbb, ncb, pfl, cz, d); + Ciecam02::xyz2jchqms_ciecam02float ( J, C, h, + Q, M, s, aw, fl, wh, + x, y, z, + xw1, yw1, zw1, + c, nc, gamu, pow1, nbb, ncb, pfl, cz, d); Jbuffer[k] = J; Cbuffer[k] = C; hbuffer[k] = h; @@ -1972,16 +1988,16 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float b = lab->b[i][j]; float x1, y1, z1; //convert Lab => XYZ - Color::Lab2XYZ(L, a, b, x1, y1, z1); + Color::Lab2XYZ (L, a, b, x1, y1, z1); x = (float)x1 / 655.35f; y = (float)y1 / 655.35f; z = (float)z1 / 655.35f; //process source==> normal - Ciecam02::xyz2jchqms_ciecam02float( J, C, h, - Q, M, s, aw, fl, wh, - x, y, z, - xw1, yw1, zw1, - c, nc, gamu, pow1, nbb, ncb, pfl, cz, d); + Ciecam02::xyz2jchqms_ciecam02float ( J, C, h, + Q, M, s, aw, fl, wh, + x, y, z, + xw1, yw1, zw1, + c, nc, gamu, pow1, nbb, ncb, pfl, cz, d); #endif float Jpro, Cpro, hpro, Qpro, Mpro, spro; Jpro = J; @@ -1992,75 +2008,75 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int spro = s; // we cannot have all algorithms with all chroma curves - if(alg == 0) { + if (alg == 0) { Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast - Qpro = QproFactor * sqrtf(Jpro); + Qpro = QproFactor * sqrtf (Jpro); float Cp = (spro * spro * Qpro) / (1000000.f); Cpro = Cp * 100.f; float sres; - Ciecam02::curvecolorfloat(chr, Cp , sres, 1.8f); - Color::skinredfloat(Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); - } else if(alg == 1) { + Ciecam02::curvecolorfloat (chr, Cp , sres, 1.8f); + Color::skinredfloat (Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); + } else if (alg == 1) { // Lightness saturation Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast float sres; float Sp = spro / 100.0f; float parsat = 1.5f; //parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation) - Ciecam02::curvecolorfloat(schr, Sp , sres, parsat); + Ciecam02::curvecolorfloat (schr, Sp , sres, parsat); float dred = 100.f; // in C mode float protect_red = 80.0f; // in C mode - dred = 100.0f * sqrtf((dred * coe) / Qpro); - protect_red = 100.0f * sqrtf((protect_red * coe) / Qpro); - Color::skinredfloat(Jpro, hpro, sres, Sp, dred, protect_red, 0, rstprotection, 100.f, spro); - Qpro = QproFactor * sqrtf(Jpro); + dred = 100.0f * sqrtf ((dred * coe) / Qpro); + protect_red = 100.0f * sqrtf ((protect_red * coe) / Qpro); + Color::skinredfloat (Jpro, hpro, sres, Sp, dred, protect_red, 0, rstprotection, 100.f, spro); + Qpro = QproFactor * sqrtf (Jpro); Cpro = (spro * spro * Qpro) / (10000.0f); - } else if(alg == 2) { - Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)]; //brightness and contrast + } else if (alg == 2) { + Qpro = CAMBrightCurveQ[ (float) (Qpro * coefQ)]; //brightness and contrast float Mp, sres; Mp = Mpro / 100.0f; - Ciecam02::curvecolorfloat(mchr, Mp , sres, 2.5f); + Ciecam02::curvecolorfloat (mchr, Mp , sres, 2.5f); float dred = 100.f; //in C mode float protect_red = 80.0f; // in C mode dred *= coe; //in M mode protect_red *= coe; //M mode - Color::skinredfloat(Jpro, hpro, sres, Mp, dred, protect_red, 0, rstprotection, 100.f, Mpro); - Jpro = SQR((10.f * Qpro) / wh); + Color::skinredfloat (Jpro, hpro, sres, Mp, dred, protect_red, 0, rstprotection, 100.f, Mpro); + Jpro = SQR ((10.f * Qpro) / wh); Cpro = Mpro / coe; Qpro = (Qpro == 0.f ? epsil : Qpro); // avoid division by zero - spro = 100.0f * sqrtf( Mpro / Qpro ); + spro = 100.0f * sqrtf ( Mpro / Qpro ); } else { /*if(alg == 3) */ - Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)]; //brightness and contrast + Qpro = CAMBrightCurveQ[ (float) (Qpro * coefQ)]; //brightness and contrast float Mp, sres; Mp = Mpro / 100.0f; - Ciecam02::curvecolorfloat(mchr, Mp , sres, 2.5f); + Ciecam02::curvecolorfloat (mchr, Mp , sres, 2.5f); float dred = 100.f; //in C mode float protect_red = 80.0f; // in C mode dred *= coe; //in M mode protect_red *= coe; //M mode - Color::skinredfloat(Jpro, hpro, sres, Mp, dred, protect_red, 0, rstprotection, 100.f, Mpro); - Jpro = SQR((10.f * Qpro) / wh); + Color::skinredfloat (Jpro, hpro, sres, Mp, dred, protect_red, 0, rstprotection, 100.f, Mpro); + Jpro = SQR ((10.f * Qpro) / wh); Cpro = Mpro / coe; Qpro = (Qpro == 0.f ? epsil : Qpro); // avoid division by zero - spro = 100.0f * sqrtf( Mpro / Qpro ); + spro = 100.0f * sqrtf ( Mpro / Qpro ); - if(Jpro > 99.9f) { + if (Jpro > 99.9f) { Jpro = 99.9f; } - Jpro = CAMBrightCurveJ[(float)(Jpro * 327.68f)]; //lightness CIECAM02 + contrast + Jpro = CAMBrightCurveJ[ (float) (Jpro * 327.68f)]; //lightness CIECAM02 + contrast float Sp = spro / 100.0f; - Ciecam02::curvecolorfloat(schr, Sp , sres, 1.5f); + Ciecam02::curvecolorfloat (schr, Sp , sres, 1.5f); dred = 100.f; // in C mode protect_red = 80.0f; // in C mode - dred = 100.0f * sqrtf((dred * coe) / Q); - protect_red = 100.0f * sqrtf((protect_red * coe) / Q); - Color::skinredfloat(Jpro, hpro, sres, Sp, dred, protect_red, 0, rstprotection, 100.f, spro); - Qpro = QproFactor * sqrtf(Jpro); + dred = 100.0f * sqrtf ((dred * coe) / Q); + protect_red = 100.0f * sqrtf ((protect_red * coe) / Q); + Color::skinredfloat (Jpro, hpro, sres, Sp, dred, protect_red, 0, rstprotection, 100.f, spro); + Qpro = QproFactor * sqrtf (Jpro); float Cp = (spro * spro * Qpro) / (1000000.f); Cpro = Cp * 100.f; - Ciecam02::curvecolorfloat(chr, Cp , sres, 1.8f); - Color::skinredfloat(Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); + Ciecam02::curvecolorfloat (chr, Cp , sres, 1.8f); + Color::skinredfloat (Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); // disabled this code, Issue 2690 // if(Jpro < 1.f && Cpro > 12.f) Cpro=12.f;//reduce artifacts by "pseudo gamut control CIECAM" // else if(Jpro < 2.f && Cpro > 15.f) Cpro=15.f; @@ -2068,7 +2084,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int // else if(Jpro < 7.f && Cpro > 50.f) Cpro=50.f; hpro = hpro + hue; - if( hpro < 0.0f ) { + if ( hpro < 0.0f ) { hpro += 360.0f; //hue } } @@ -2080,27 +2096,27 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float Jold100 = (float) Jpro; float redu = 25.f; float reduc = 1.f; - const Lightcurve& userColCurveJ1 = static_cast<const Lightcurve&>(customColCurve1); - userColCurveJ1.Apply(Jj); + const Lightcurve& userColCurveJ1 = static_cast<const Lightcurve&> (customColCurve1); + userColCurveJ1.Apply (Jj); - if(Jj > Jold) { - if(Jj < 65535.f) { - if(Jold < 327.68f * redu) { + if (Jj > Jold) { + if (Jj < 65535.f) { + if (Jold < 327.68f * redu) { Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility } else { - reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM ((100.f - Jold100) / (100.f - redu), 0.f, 1.f); Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } } - } else if(Jj > 10.f) { + } else if (Jj > 10.f) { Jj = 0.8f * (Jj - Jold) + Jold; } else if (Jj >= 0.f) { Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts } - Jpro = (float)(Jj / 327.68f); + Jpro = (float) (Jj / 327.68f); - if(Jpro < 1.f) { + if (Jpro < 1.f) { Jpro = 1.f; } } else if (curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { @@ -2113,28 +2129,28 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float redu = 20.f; float reduc = 1.f; - const Brightcurve& userColCurveB1 = static_cast<const Brightcurve&>(customColCurve1); - userColCurveB1.Apply(Qq); + const Brightcurve& userColCurveB1 = static_cast<const Brightcurve&> (customColCurve1); + userColCurveB1.Apply (Qq); - if(Qq > Qold) { - if(Qq < 65535.f) { - if(Qold < 327.68f * redu) { + if (Qq > Qold) { + if (Qq < 65535.f) { + if (Qold < 327.68f * redu) { Qq = 0.25f * (Qq - Qold) + Qold; //divide sensibility } else { - reduc = LIM((100.f - Qold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM ((100.f - Qold100) / (100.f - redu), 0.f, 1.f); Qq = 0.25f * reduc * (Qq - Qold) + Qold; //reduct sensibility in highlights } } - } else if(Qq > 10.f) { + } else if (Qq > 10.f) { Qq = 0.5f * (Qq - Qold) + Qold; } else if (Qq >= 0.f) { Qq = 0.7f * (Qq - Qold) + Qold; // not zero ==>artifacts } - Qpro = (float)(Qq * (coef) / 327.68f); + Qpro = (float) (Qq * (coef) / 327.68f); Jpro = 100.f * (Qpro * Qpro) / ((4.0f / c) * (4.0f / c) * (aw + 4.0f) * (aw + 4.0f)); - if(Jpro < 1.f) { + if (Jpro < 1.f) { Jpro = 1.f; } } @@ -2147,35 +2163,35 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float Jold100 = (float) Jpro; float redu = 25.f; float reduc = 1.f; - const Lightcurve& userColCurveJ2 = static_cast<const Lightcurve&>(customColCurve2); - userColCurveJ2.Apply(Jj); + const Lightcurve& userColCurveJ2 = static_cast<const Lightcurve&> (customColCurve2); + userColCurveJ2.Apply (Jj); - if(Jj > Jold) { - if(Jj < 65535.f) { - if(Jold < 327.68f * redu) { + if (Jj > Jold) { + if (Jj < 65535.f) { + if (Jold < 327.68f * redu) { Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility } else { - reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM ((100.f - Jold100) / (100.f - redu), 0.f, 1.f); Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } } - } else if(Jj > 10.f) { - if(!t1L) { + } else if (Jj > 10.f) { + if (!t1L) { Jj = 0.8f * (Jj - Jold) + Jold; } else { Jj = 0.4f * (Jj - Jold) + Jold; } } else if (Jj >= 0.f) { - if(!t1L) { + if (!t1L) { Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts } else { Jj = 0.5f * (Jj - Jold) + Jold; } } - Jpro = (float)(Jj / 327.68f); + Jpro = (float) (Jj / 327.68f); - if(Jpro < 1.f) { + if (Jpro < 1.f) { Jpro = 1.f; } @@ -2188,39 +2204,39 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float redu = 20.f; float reduc = 1.f; - const Brightcurve& userColCurveB2 = static_cast<const Brightcurve&>(customColCurve2); - userColCurveB2.Apply(Qq); + const Brightcurve& userColCurveB2 = static_cast<const Brightcurve&> (customColCurve2); + userColCurveB2.Apply (Qq); - if(Qq > Qold) { - if(Qq < 65535.f) { - if(Qold < 327.68f * redu) { + if (Qq > Qold) { + if (Qq < 65535.f) { + if (Qold < 327.68f * redu) { Qq = 0.25f * (Qq - Qold) + Qold; //divide sensibility } else { - reduc = LIM((100.f - Qold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM ((100.f - Qold100) / (100.f - redu), 0.f, 1.f); Qq = 0.25f * reduc * (Qq - Qold) + Qold; //reduct sensibility in highlights } } - } else if(Qq > 10.f) { + } else if (Qq > 10.f) { Qq = 0.5f * (Qq - Qold) + Qold; } else if (Qq >= 0.f) { Qq = 0.7f * (Qq - Qold) + Qold; // not zero ==>artifacts } - Qpro = (float)(Qq * (coef) / 327.68f); + Qpro = (float) (Qq * (coef) / 327.68f); Jpro = 100.f * (Qpro * Qpro) / ((4.0f / c) * (4.0f / c) * (aw + 4.0f) * (aw + 4.0f)); - if(t1L) { //to workaround the problem if we modify curve1-lightnees after curve2 brightness(the cat that bites its own tail!) in fact it's another type of curve only for this case + if (t1L) { //to workaround the problem if we modify curve1-lightnees after curve2 brightness(the cat that bites its own tail!) in fact it's another type of curve only for this case coef = 2.f; //adapt Q to J approximation Qq = (float) Qpro * coef; Qold = Qq; - const Lightcurve& userColCurveJ1 = static_cast<const Lightcurve&>(customColCurve1); - userColCurveJ1.Apply(Qq); + const Lightcurve& userColCurveJ1 = static_cast<const Lightcurve&> (customColCurve1); + userColCurveJ1.Apply (Qq); Qq = 0.05f * (Qq - Qold) + Qold; //approximative adaptation - Qpro = (float)(Qq / coef); + Qpro = (float) (Qq / coef); Jpro = 100.f * (Qpro * Qpro) / ((4.0f / c) * (4.0f / c) * (aw + 4.0f) * (aw + 4.0f)); } - if(Jpro < 1.f) { + if (Jpro < 1.f) { Jpro = 1.f; } } @@ -2232,13 +2248,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float coef = 327.68f / parsat; float Cc = (float) Cpro * coef; float Ccold = Cc; - const Chromacurve& userColCurve = static_cast<const Chromacurve&>(customColCurve3); - userColCurve.Apply(Cc); + const Chromacurve& userColCurve = static_cast<const Chromacurve&> (customColCurve3); + userColCurve.Apply (Cc); float dred = 55.f; float protect_red = 30.0f; int sk = 1; float ko = 1.f / coef; - Color::skinredfloat(Jpro, hpro, Cc, Ccold, dred, protect_red, sk, rstprotection, ko, Cpro); + Color::skinredfloat (Jpro, hpro, Cc, Ccold, dred, protect_red, sk, rstprotection, ko, Cpro); /* if(Jpro < 1.f && Cpro > 12.f) { Cpro = 12.f; //reduce artifacts by "pseudo gamut control CIECAM" @@ -2255,32 +2271,32 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float coef = 327.68f / parsat; float Ss = (float) spro * coef; float Sold = Ss; - const Saturcurve& userColCurve = static_cast<const Saturcurve&>(customColCurve3); - userColCurve.Apply(Ss); + const Saturcurve& userColCurve = static_cast<const Saturcurve&> (customColCurve3); + userColCurve.Apply (Ss); Ss = 0.6f * (Ss - Sold) + Sold; //divide sensibility saturation float dred = 100.f; // in C mode float protect_red = 80.0f; // in C mode - dred = 100.0f * sqrtf((dred * coe) / Qpro); - protect_red = 100.0f * sqrtf((protect_red * coe) / Qpro); + dred = 100.0f * sqrtf ((dred * coe) / Qpro); + protect_red = 100.0f * sqrtf ((protect_red * coe) / Qpro); int sk = 0; float ko = 1.f / coef; - Color::skinredfloat(Jpro, hpro, Ss, Sold, dred, protect_red, sk, rstprotection, ko, spro); - Qpro = ( 4.0f / c ) * sqrtf( Jpro / 100.0f ) * ( aw + 4.0f ) ; + Color::skinredfloat (Jpro, hpro, Ss, Sold, dred, protect_red, sk, rstprotection, ko, spro); + Qpro = ( 4.0f / c ) * sqrtf ( Jpro / 100.0f ) * ( aw + 4.0f ) ; Cpro = (spro * spro * Qpro) / (10000.0f); } else if (curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { // float parsat = 0.8f; //0.68; float coef = 327.68f / parsat; float Mm = (float) Mpro * coef; float Mold = Mm; - const Colorfcurve& userColCurve = static_cast<const Colorfcurve&>(customColCurve3); - userColCurve.Apply(Mm); + const Colorfcurve& userColCurve = static_cast<const Colorfcurve&> (customColCurve3); + userColCurve.Apply (Mm); float dred = 100.f; //in C mode float protect_red = 80.0f; // in C mode dred *= coe; //in M mode protect_red *= coe; int sk = 0; float ko = 1.f / coef; - Color::skinredfloat(Jpro, hpro, Mm, Mold, dred, protect_red, sk, rstprotection, ko, Mpro); + Color::skinredfloat (Jpro, hpro, Mm, Mold, dred, protect_red, sk, rstprotection, ko, Mpro); /* if(Jpro < 1.f && Mpro > 12.f * coe) { Mpro = 12.f * coe; //reduce artifacts by "pseudo gamut control CIECAM" @@ -2307,28 +2323,28 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int h = hpro; s = spro; - if(params->colorappearance.tonecie || settings->autocielab) { //use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail + if (params->colorappearance.tonecie || settings->autocielab) { //use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail ncie->Q_p[i][j] = (float)Q + epsil; //epsil to avoid Q=0 ncie->M_p[i][j] = (float)M + epsil; ncie->J_p[i][j] = (float)J + epsil; ncie->h_p[i][j] = (float)h; ncie->C_p[i][j] = (float)C + epsil; - ncie->sh_p[i][j] = (float) 3276.8f * (sqrtf( J ) ) ; + ncie->sh_p[i][j] = (float) 3276.8f * (sqrtf ( J ) ) ; - if(epdEnabled) { - if(ncie->Q_p[i][j] < minQThr) { + if (epdEnabled) { + if (ncie->Q_p[i][j] < minQThr) { minQThr = ncie->Q_p[i][j]; //minima } - if(ncie->Q_p[i][j] > maxQThr) { + if (ncie->Q_p[i][j] > maxQThr) { maxQThr = ncie->Q_p[i][j]; //maxima } } } - if(!params->colorappearance.tonecie || !settings->autocielab || !epdEnabled) { + if (!params->colorappearance.tonecie || !settings->autocielab || !epdEnabled) { - if(ciedata) { //only with improccoordinator + if (ciedata) { //only with improccoordinator // Data for J Q M s and C histograms int posl, posc; float brli = 327.f; @@ -2337,7 +2353,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float colch; //update histogram - if(curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { + if (curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { brli = 70.0f; libr = Q; //40.0 to 100.0 approximative factor for Q - 327 for J } else { /*if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT)*/ @@ -2345,13 +2361,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int libr = J; //327 for J } - posl = (int)(libr * brli); + posl = (int) (libr * brli); hist16JCAM[posl]++; if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { chsacol = 327.f; colch = C; //450.0 approximative factor for s 320 for M - } else if(curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { + } else if (curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0f; colch = s; } else { /*if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF)*/ @@ -2359,12 +2375,12 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int colch = M; } - posc = (int)(colch * chsacol); + posc = (int) (colch * chsacol); hist16_CCAM[posc]++; } - if(LabPassOne) { + if (LabPassOne) { #ifdef __SSE2__ // write to line buffers Jbuffer[j] = J; @@ -2374,27 +2390,27 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float xx, yy, zz; //process normal==> viewing - Ciecam02::jch2xyz_ciecam02float( xx, yy, zz, - J, C, h, - xw2, yw2, zw2, - f2, c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj); + Ciecam02::jch2xyz_ciecam02float ( xx, yy, zz, + J, C, h, + xw2, yw2, zw2, + f2, c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj); float x, y, z; x = xx * 655.35f; y = yy * 655.35f; z = zz * 655.35f; float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab(x, y, z, Ll, aa, bb); + Color::XYZ2Lab (x, y, z, Ll, aa, bb); // gamut control in Lab mode; I must study how to do with cIECAM only - if(gamu == 1) { + if (gamu == 1) { float HH, Lprov1, Chprov1; Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; - HH = xatan2f(bb, aa); + Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; + HH = xatan2f (bb, aa); float2 sincosval; - if(Chprov1 == 0.0f) { + if (Chprov1 == 0.0f) { sincosval.y = 1.f; sincosval.x = 0.0f; } else { @@ -2407,10 +2423,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; @@ -2434,31 +2450,31 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float *ybuffer = Mbuffer; float *zbuffer = sbuffer; - for(k = 0; k < bufferLength; k += 4) { - Ciecam02::jch2xyz_ciecam02float( x, y, z, - LVF(Jbuffer[k]), LVF(Cbuffer[k]), LVF(hbuffer[k]), - F2V(xw2), F2V(yw2), F2V(zw2), - F2V(f2), F2V(nc2), F2V(pow1n), F2V(nbbj), F2V(ncbj), F2V(flj), F2V(dj), F2V(awj), F2V(reccmcz)); - STVF(xbuffer[k], x * c655d35); - STVF(ybuffer[k], y * c655d35); - STVF(zbuffer[k], z * c655d35); + for (k = 0; k < bufferLength; k += 4) { + Ciecam02::jch2xyz_ciecam02float ( x, y, z, + LVF (Jbuffer[k]), LVF (Cbuffer[k]), LVF (hbuffer[k]), + F2V (xw2), F2V (yw2), F2V (zw2), + F2V (f2), F2V (nc2), F2V (pow1n), F2V (nbbj), F2V (ncbj), F2V (flj), F2V (dj), F2V (awj), F2V (reccmcz)); + STVF (xbuffer[k], x * c655d35); + STVF (ybuffer[k], y * c655d35); + STVF (zbuffer[k], z * c655d35); } // XYZ2Lab uses a lookup table. The function behind that lut is a cube root. // SSE can't beat the speed of that lut, so it doesn't make sense to use SSE - for(int j = 0; j < width; j++) { + for (int j = 0; j < width; j++) { float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab(xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); + Color::XYZ2Lab (xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); // gamut control in Lab mode; I must study how to do with cIECAM only - if(gamu == 1) { + if (gamu == 1) { float Lprov1, Chprov1; Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; + Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; float2 sincosval; - if(Chprov1 == 0.0f) { + if (Chprov1 == 0.0f) { sincosval.y = 1.f; sincosval.x = 0.0f; } else { @@ -2470,10 +2486,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; @@ -2490,24 +2506,24 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int #pragma omp critical { - if(minQThr < minQ) { + if (minQThr < minQ) { minQ = minQThr; } - if(maxQThr > maxQ) { + if (maxQThr > maxQ) { maxQ = maxQThr; } } } // End of parallelization - if(!params->colorappearance.tonecie || !settings->autocielab) { //normal + if (!params->colorappearance.tonecie || !settings->autocielab) { //normal - if(ciedata) { + if (ciedata) { //update histogram J - hist16JCAM.compressTo(histLCAM); + hist16JCAM.compressTo (histLCAM); //update histogram C - hist16_CCAM.compressTo(histCCAM); + hist16_CCAM.compressTo (histCCAM); } } @@ -2515,14 +2531,14 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int if (settings->verbose) { t2e.set(); - printf("CIECAM02 performed in %d usec:\n", t2e.etime(t1e)); + printf ("CIECAM02 performed in %d usec:\n", t2e.etime (t1e)); // printf("minc=%f maxc=%f minj=%f maxj=%f\n",minc,maxc,minj,maxj); } #endif - if(settings->autocielab) { - if((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) + if (settings->autocielab) { + if ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)) { @@ -2530,27 +2546,27 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //all this treatments reduce artefacts, but can leed to slighty different results - if(params->defringe.enabled) - if(execsharp) { + if (params->defringe.enabled) + if (execsharp) { lab->deleteLab(); ImProcFunctions::defringecam (ncie);//defringe adapted to CIECAM lab->reallocLab(); } //if(params->dirpyrequalizer.enabled) if(execsharp) { - if(params->dirpyrequalizer.enabled) { - if(params->dirpyrequalizer.gamutlab /*&& execsharp*/) {//remove artifacts by gaussian blur - skin control - float b_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[0]) / 100.0f; - float t_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[1]) / 100.0f; - float b_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[2]) / 100.0f; - float t_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[3]) / 100.0f; + if (params->dirpyrequalizer.enabled) { + if (params->dirpyrequalizer.gamutlab /*&& execsharp*/) { //remove artifacts by gaussian blur - skin control + float b_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[0]) / 100.0f; + float t_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[1]) / 100.0f; + float b_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[2]) / 100.0f; + float t_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[3]) / 100.0f; float artifact = (float) settings->artifact_cbdl; - if(artifact > 6.f) { + if (artifact > 6.f) { artifact = 6.f; } - if(artifact < 0.f) { + if (artifact < 0.f) { artifact = 1.f; } @@ -2563,14 +2579,14 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } //if(params->colorappearance.badpixsl > 0) { int mode=params->colorappearance.badpixsl; - if(params->colorappearance.badpixsl > 0) if(execsharp) { + if (params->colorappearance.badpixsl > 0) if (execsharp) { int mode = params->colorappearance.badpixsl; lab->deleteLab(); ImProcFunctions::badpixcam (ncie, 3.0, 10, mode, 0, 0, 0, 0, 0, 0, 1);//for bad pixels CIECAM lab->reallocLab(); } - if(params->impulseDenoise.enabled) if(execsharp) { + if (params->impulseDenoise.enabled) if (execsharp) { float **buffers[3]; buffers[0] = lab->L; buffers[1] = lab->a; @@ -2578,29 +2594,29 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int ImProcFunctions::impulsedenoisecam (ncie, buffers); //impulse adapted to CIECAM } - if (params->sharpenMicro.enabled)if(execsharp) { - ImProcFunctions::MLmicrocontrastcam(ncie); + if (params->sharpenMicro.enabled)if (execsharp) { + ImProcFunctions::MLmicrocontrastcam (ncie); } - if(params->sharpening.enabled) - if(execsharp) { + if (params->sharpening.enabled) + if (execsharp) { float **buffer = lab->L; // We can use the L-buffer from lab as buffer to save some memory ImProcFunctions::sharpeningcam (ncie, buffer); // sharpening adapted to CIECAM } //if(params->dirpyrequalizer.enabled) if(execsharp) { - if(params->dirpyrequalizer.enabled /*&& execsharp*/) { + if (params->dirpyrequalizer.enabled /*&& execsharp*/) { // if(params->dirpyrequalizer.algo=="FI") choice=0; // else if(params->dirpyrequalizer.algo=="LA") choice=1; - if(rtt == 1) { - float b_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[0]) / 100.0f; - float t_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[1]) / 100.0f; - float b_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[2]) / 100.0f; - float t_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[3]) / 100.0f; + if (rtt == 1) { + float b_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[0]) / 100.0f; + float t_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[1]) / 100.0f; + float b_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[2]) / 100.0f; + float t_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[3]) / 100.0f; int choice = 0; // I have not suppress this statement in case of !! always to 0 lab->deleteLab(); - dirpyr_equalizercam(ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, ncie->h_p, ncie->C_p, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, true, params->dirpyrequalizer.gamutlab, b_l, t_l, t_r, b_r, choice, scalecd); //contrast by detail adapted to CIECAM + dirpyr_equalizercam (ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, ncie->h_p, ncie->C_p, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, true, params->dirpyrequalizer.gamutlab, b_l, t_l, t_r, b_r, choice, scalecd); //contrast by detail adapted to CIECAM lab->reallocLab(); } @@ -2613,7 +2629,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } const float Qredi = ( 4.0f / c_) * ( a_w + 4.0f ); - const float co_e = (pow_F(f_l, 0.25f)); + const float co_e = (pow_F (f_l, 0.25f)); #ifndef _DEBUG @@ -2626,8 +2642,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int for (int i = 0; i < height; i++) // update CieImages with new values after sharpening, defringe, contrast by detail level for (int j = 0; j < width; j++) { - float interm = fabsf(ncie->sh_p[i][j] / (32768.f)); - ncie->J_p[i][j] = 100.0f * SQR(interm); + float interm = fabsf (ncie->sh_p[i][j] / (32768.f)); + ncie->J_p[i][j] = 100.0f * SQR (interm); ncie->Q_p[i][j] = interm * Qredi; ncie->M_p[i][j] = ncie->C_p[i][j] * co_e; } @@ -2635,15 +2651,15 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } } - if((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) + if ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)) { ciedata = (params->colorappearance.datacie && pW != 1); - if(epdEnabled && params->colorappearance.tonecie && algepd) { + if (epdEnabled && params->colorappearance.tonecie && algepd) { lab->deleteLab(); - ImProcFunctions::EPDToneMapCIE(ncie, a_w, c_, w_h, width, height, begh, endh, minQ, maxQ, Iterates, scale ); + ImProcFunctions::EPDToneMapCIE (ncie, a_w, c_, w_h, width, height, begh, endh, minQ, maxQ, Iterates, scale ); lab->reallocLab(); } @@ -2651,7 +2667,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int constexpr float eps = 0.0001f; - const float co_e = (pow_F(f_l, 0.25f)) + eps; + const float co_e = (pow_F (f_l, 0.25f)) + eps; #ifndef _DEBUG #pragma omp parallel @@ -2675,14 +2691,14 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int for (int j = 0; j < width; j++) { // 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) { - ncie->J_p[i][j] = (100.0f * ncie->Q_p[i][j] * ncie->Q_p[i][j]) / SQR((4.f / c) * (aw + 4.f)); + if (epdEnabled) { + ncie->J_p[i][j] = (100.0f * ncie->Q_p[i][j] * ncie->Q_p[i][j]) / SQR ((4.f / c) * (aw + 4.f)); } const float ncie_C_p = (ncie->M_p[i][j]) / co_e; //show histogram in CIECAM mode (Q,J, M,s,C) - if(ciedata) { + if (ciedata) { // Data for J Q M s and C histograms int posl, posc; float brli = 327.f; @@ -2690,7 +2706,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float libr; float colch; - if(curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { + if (curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { brli = 70.0f; libr = ncie->Q_p[i][j]; //40.0 to 100.0 approximative factor for Q - 327 for J } else { /*if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT)*/ @@ -2698,21 +2714,21 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int libr = ncie->J_p[i][j]; //327 for J } - posl = (int)(libr * brli); + posl = (int) (libr * brli); hist16JCAM[posl]++; if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { chsacol = 327.f; colch = ncie_C_p; - } else if(curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { + } else if (curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0f; - colch = 100.f * sqrtf(ncie_C_p / ncie->Q_p[i][j]); + colch = 100.f * sqrtf (ncie_C_p / ncie->Q_p[i][j]); } else { /*if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF)*/ chsacol = 327.0f; colch = ncie->M_p[i][j]; } - posc = (int)(colch * chsacol); + posc = (int) (colch * chsacol); hist16_CCAM[posc]++; } @@ -2724,24 +2740,24 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int hbuffer[j] = ncie->h_p[i][j]; #else float xx, yy, zz; - Ciecam02::jch2xyz_ciecam02float( xx, yy, zz, - ncie->J_p[i][j], ncie_C_p, ncie->h_p[i][j], - xw2, yw2, zw2, - f2, c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj); + Ciecam02::jch2xyz_ciecam02float ( xx, yy, zz, + ncie->J_p[i][j], ncie_C_p, ncie->h_p[i][j], + xw2, yw2, zw2, + f2, c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj); float x = (float)xx * 655.35f; float y = (float)yy * 655.35f; float z = (float)zz * 655.35f; float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab(x, y, z, Ll, aa, bb); + Color::XYZ2Lab (x, y, z, Ll, aa, bb); - if(gamu == 1) { + if (gamu == 1) { float Lprov1, Chprov1; Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; + Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; float2 sincosval; - if(Chprov1 == 0.0f) { + if (Chprov1 == 0.0f) { sincosval.y = 1.f; sincosval.x = 0.0f; } else { @@ -2754,10 +2770,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; @@ -2776,35 +2792,35 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int // process line buffers int k; vfloat x, y, z; - vfloat c655d35 = F2V(655.35f); + vfloat c655d35 = F2V (655.35f); - for(k = 0; k < bufferLength; k += 4) { - Ciecam02::jch2xyz_ciecam02float( x, y, z, - LVF(Jbuffer[k]), LVF(Cbuffer[k]), LVF(hbuffer[k]), - F2V(xw2), F2V(yw2), F2V(zw2), - F2V(f2), F2V(nc2), F2V(pow1n), F2V(nbbj), F2V(ncbj), F2V(flj), F2V(dj), F2V(awj), F2V(reccmcz)); + for (k = 0; k < bufferLength; k += 4) { + Ciecam02::jch2xyz_ciecam02float ( x, y, z, + LVF (Jbuffer[k]), LVF (Cbuffer[k]), LVF (hbuffer[k]), + F2V (xw2), F2V (yw2), F2V (zw2), + F2V (f2), F2V (nc2), F2V (pow1n), F2V (nbbj), F2V (ncbj), F2V (flj), F2V (dj), F2V (awj), F2V (reccmcz)); x *= c655d35; y *= c655d35; z *= c655d35; - STVF(xbuffer[k], x); - STVF(ybuffer[k], y); - STVF(zbuffer[k], z); + STVF (xbuffer[k], x); + STVF (ybuffer[k], y); + STVF (zbuffer[k], z); } // XYZ2Lab uses a lookup table. The function behind that lut is a cube root. // SSE can't beat the speed of that lut, so it doesn't make sense to use SSE - for(int j = 0; j < width; j++) { + for (int j = 0; j < width; j++) { float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab(xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); + Color::XYZ2Lab (xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); - if(gamu == 1) { + if (gamu == 1) { float Lprov1, Chprov1; Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; + Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; float2 sincosval; - if(Chprov1 == 0.0f) { + if (Chprov1 == 0.0f) { sincosval.y = 1.f; sincosval.x = 0.0f; } else { @@ -2816,10 +2832,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; @@ -2838,13 +2854,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } //end parallelization //show CIECAM histograms - if(ciedata) { + if (ciedata) { //update histogram J and Q //update histogram J - hist16JCAM.compressTo(histLCAM); + hist16JCAM.compressTo (histLCAM); //update color histogram M,s,C - hist16_CCAM.compressTo(histCCAM); + hist16_CCAM.compressTo (histCCAM); } } } @@ -2866,20 +2882,20 @@ void ImProcFunctions::moyeqt (Imagefloat* working, float &moyS, float &eqty) for (int i = 0; i < tHh; i++) { for (int j = 0; j < tWw; j++) { - float s = Color::rgb2s(CLIP(working->r(i, j)), CLIP(working->g(i, j)), CLIP(working->b(i, j))); + float s = Color::rgb2s (CLIP (working->r (i, j)), CLIP (working->g (i, j)), CLIP (working->b (i, j))); moy += s; - sqrs += SQR(s); + sqrs += SQR (s); } } moy /= (tHh * tWw); sqrs /= (tHh * tWw); - eqty = sqrt(sqrs - SQR(moy)); + eqty = sqrt (sqrs - SQR (moy)); moyS = moy; } static inline void -filmlike_clip_rgb_tone(float *r, float *g, float *b, const float L) +filmlike_clip_rgb_tone (float *r, float *g, float *b, const float L) { float r_ = *r > L ? L : *r; float b_ = *b > L ? L : *b; @@ -2890,18 +2906,18 @@ filmlike_clip_rgb_tone(float *r, float *g, float *b, const float L) } static void -filmlike_clip(float *r, float *g, float *b) +filmlike_clip (float *r, float *g, float *b) { // This is Adobe's hue-stable film-like curve with a diagonal, ie only used for clipping. Can probably be further optimized. const float L = 65535.0; if (*r >= *g) { if (*g > *b) { // Case 1: r >= g > b - filmlike_clip_rgb_tone(r, g, b, L); + filmlike_clip_rgb_tone (r, g, b, L); } else if (*b > *r) { // Case 2: b > r >= g - filmlike_clip_rgb_tone(b, r, g, L); + filmlike_clip_rgb_tone (b, r, g, L); } else if (*b > *g) { // Case 3: r >= b > g - filmlike_clip_rgb_tone(r, b, g, L); + filmlike_clip_rgb_tone (r, b, g, L); } else { // Case 4: r >= g == b *r = *r > L ? L : *r; *g = *g > L ? L : *g; @@ -2909,11 +2925,11 @@ filmlike_clip(float *r, float *g, float *b) } } else { if (*r >= *b) { // Case 5: g > r >= b - filmlike_clip_rgb_tone(g, r, b, L); + filmlike_clip_rgb_tone (g, r, b, L); } else if (*b > *g) { // Case 6: b > g > r - filmlike_clip_rgb_tone(b, g, r, L); + filmlike_clip_rgb_tone (b, g, r, L); } else { // Case 7: g >= b > r - filmlike_clip_rgb_tone(g, b, r, L); + filmlike_clip_rgb_tone (g, b, r, L); } } } @@ -2968,20 +2984,20 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float toxyz[3][3] = { { - static_cast<float>( wprof[0][0] / Color::D50x), - static_cast<float>( wprof[0][1] / Color::D50x), - static_cast<float>( wprof[0][2] / Color::D50x) + static_cast<float> ( wprof[0][0] / Color::D50x), + static_cast<float> ( wprof[0][1] / Color::D50x), + static_cast<float> ( wprof[0][2] / Color::D50x) }, { - static_cast<float>( wprof[1][0]), - static_cast<float>( wprof[1][1]), - static_cast<float>( wprof[1][2]) + static_cast<float> ( wprof[1][0]), + static_cast<float> ( wprof[1][1]), + static_cast<float> ( wprof[1][2]) }, { - static_cast<float>( wprof[2][0] / Color::D50z), - static_cast<float>( wprof[2][1] / Color::D50z), - static_cast<float>( wprof[2][2] / Color::D50z) + static_cast<float> ( wprof[2][0] / Color::D50z), + static_cast<float> ( wprof[2][1] / Color::D50z), + static_cast<float> ( wprof[2][2] / Color::D50z) } }; - float maxFactorToxyz = max(toxyz[1][0],toxyz[1][1],toxyz[1][2]); + float maxFactorToxyz = max (toxyz[1][0], toxyz[1][1], toxyz[1][2]); float equalR = maxFactorToxyz / toxyz[1][0]; float equalG = maxFactorToxyz / toxyz[1][1]; float equalB = maxFactorToxyz / toxyz[1][2]; @@ -3008,10 +3024,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer FlatCurve* vCurve = nullptr; FlatCurve* bwlCurve = nullptr; - FlatCurveType hCurveType = (FlatCurveType)params->hsvequalizer.hcurve.at(0); - FlatCurveType sCurveType = (FlatCurveType)params->hsvequalizer.scurve.at(0); - FlatCurveType vCurveType = (FlatCurveType)params->hsvequalizer.vcurve.at(0); - FlatCurveType bwlCurveType = (FlatCurveType)params->blackwhite.luminanceCurve.at(0); + FlatCurveType hCurveType = (FlatCurveType)params->hsvequalizer.hcurve.at (0); + FlatCurveType sCurveType = (FlatCurveType)params->hsvequalizer.scurve.at (0); + FlatCurveType vCurveType = (FlatCurveType)params->hsvequalizer.vcurve.at (0); + FlatCurveType bwlCurveType = (FlatCurveType)params->blackwhite.luminanceCurve.at (0); bool hCurveEnabled = hCurveType > FCT_Linear; bool sCurveEnabled = sCurveType > FCT_Linear; bool vCurveEnabled = vCurveType > FCT_Linear; @@ -3019,7 +3035,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // TODO: We should create a 'skip' value like for CurveFactory::complexsgnCurve (rtengine/curves.cc) if (hCurveEnabled) { - hCurve = new FlatCurve(params->hsvequalizer.hcurve); + hCurve = new FlatCurve (params->hsvequalizer.hcurve); if (hCurve->isIdentity()) { delete hCurve; @@ -3029,7 +3045,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (sCurveEnabled) { - sCurve = new FlatCurve(params->hsvequalizer.scurve); + sCurve = new FlatCurve (params->hsvequalizer.scurve); if (sCurve->isIdentity()) { delete sCurve; @@ -3039,7 +3055,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (vCurveEnabled) { - vCurve = new FlatCurve(params->hsvequalizer.vcurve); + vCurve = new FlatCurve (params->hsvequalizer.vcurve); if (vCurve->isIdentity()) { delete vCurve; @@ -3049,7 +3065,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (bwlCurveEnabled) { - bwlCurve = new FlatCurve(params->blackwhite.luminanceCurve); + bwlCurve = new FlatCurve (params->blackwhite.luminanceCurve); if (bwlCurve->isIdentity()) { delete bwlCurve; @@ -3069,23 +3085,23 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #endif if ( params->filmSimulation.enabled && !params->filmSimulation.clutFilename.empty() ) { - hald_clut = CLUTStore::getInstance().getClut( params->filmSimulation.clutFilename ); + hald_clut = CLUTStore::getInstance().getClut ( params->filmSimulation.clutFilename ); if ( hald_clut ) { clutAndWorkingProfilesAreSame = hald_clut->getProfile() == params->icm.working; if ( !clutAndWorkingProfilesAreSame ) { - xyz2clut = ICCStore::getInstance()->workingSpaceInverseMatrix( hald_clut->getProfile() ); - clut2xyz = ICCStore::getInstance()->workingSpaceMatrix( hald_clut->getProfile() ); + xyz2clut = ICCStore::getInstance()->workingSpaceInverseMatrix ( hald_clut->getProfile() ); + clut2xyz = ICCStore::getInstance()->workingSpaceMatrix ( hald_clut->getProfile() ); #ifdef __SSE2__ for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - v_work2xyz[i][j] = F2V(wprof[i][j]); - v_xyz2clut[i][j] = F2V(xyz2clut[i][j]); - v_xyz2work[i][j] = F2V(wiprof[i][j]); - v_clut2xyz[i][j] = F2V(clut2xyz[i][j]); + v_work2xyz[i][j] = F2V (wprof[i][j]); + v_xyz2clut[i][j] = F2V (xyz2clut[i][j]); + v_xyz2work[i][j] = F2V (wiprof[i][j]); + v_clut2xyz[i][j] = F2V (clut2xyz[i][j]); } } @@ -3095,41 +3111,41 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } } - const float film_simulation_strength = static_cast<float>(params->filmSimulation.strength) / 100.0f; + const float film_simulation_strength = static_cast<float> (params->filmSimulation.strength) / 100.0f; const float exp_scale = pow (2.0, expcomp); - const float comp = (max(0.0, expcomp) + 1.0) * hlcompr / 100.0; - const float shoulder = ((65536.0 / max(1.0f, exp_scale)) * (hlcomprthresh / 200.0)) + 0.1; + const float comp = (max (0.0, expcomp) + 1.0) * hlcompr / 100.0; + const float shoulder = ((65536.0 / max (1.0f, exp_scale)) * (hlcomprthresh / 200.0)) + 0.1; const float hlrange = 65536.0 - shoulder; const bool isProPhoto = (params->icm.working == "ProPhoto"); // extracting datas from 'params' to avoid cache flush (to be confirmed) ToneCurveParams::eTCModeId curveMode = params->toneCurve.curveMode; ToneCurveParams::eTCModeId curveMode2 = params->toneCurve.curveMode2; bool highlight = params->toneCurve.hrenabled;//Get the value if "highlight reconstruction" is activated - bool hasToneCurve1 = bool(customToneCurve1); - bool hasToneCurve2 = bool(customToneCurve2); + bool hasToneCurve1 = bool (customToneCurve1); + bool hasToneCurve2 = bool (customToneCurve2); BlackWhiteParams::eTCModeId beforeCurveMode = params->blackwhite.beforeCurveMode; BlackWhiteParams::eTCModeId afterCurveMode = params->blackwhite.afterCurveMode; - bool hasToneCurvebw1 = bool(customToneCurvebw1); - bool hasToneCurvebw2 = bool(customToneCurvebw2); + bool hasToneCurvebw1 = bool (customToneCurvebw1); + bool hasToneCurvebw2 = bool (customToneCurvebw2); PerceptualToneCurveState ptc1ApplyState, ptc2ApplyState; if (hasToneCurve1 && curveMode == ToneCurveParams::TC_MODE_PERCEPTUAL) { - const PerceptualToneCurve& userToneCurve = static_cast<const PerceptualToneCurve&>(customToneCurve1); - userToneCurve.initApplyState(ptc1ApplyState, params->icm.working); + const PerceptualToneCurve& userToneCurve = static_cast<const PerceptualToneCurve&> (customToneCurve1); + userToneCurve.initApplyState (ptc1ApplyState, params->icm.working); } if (hasToneCurve2 && curveMode2 == ToneCurveParams::TC_MODE_PERCEPTUAL) { - const PerceptualToneCurve& userToneCurve = static_cast<const PerceptualToneCurve&>(customToneCurve2); - userToneCurve.initApplyState(ptc2ApplyState, params->icm.working); + const PerceptualToneCurve& userToneCurve = static_cast<const PerceptualToneCurve&> (customToneCurve2); + userToneCurve.initApplyState (ptc2ApplyState, params->icm.working); } - bool hasColorToning = params->colorToning.enabled && bool(ctOpacityCurve) && bool(ctColorCurve); + bool hasColorToning = params->colorToning.enabled && bool (ctOpacityCurve) && bool (ctColorCurve); // float satLimit = float(params->colorToning.satProtectionThreshold)/100.f*0.7f+0.3f; // float satLimitOpacity = 1.f-(float(params->colorToning.saturatedOpacity)/100.f); - float strProtect = (float(params->colorToning.strength) / 100.f); + float strProtect = (float (params->colorToning.strength) / 100.f); /* // Debug output - Color LUTf points @@ -3161,52 +3177,52 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } */ - float RedLow = (100.f + float(params->colorToning.redlow)) / 100.f; //printf("Rel=%f\n",RedLow); - float GreenLow = (100.f + float(params->colorToning.greenlow)) / 100.f; //printf("Gre=%f\n",GreenLow); - float BlueLow = (100.f + float(params->colorToning.bluelow)) / 100.f; //printf("Blu=%f\n",BlueLow); - float RedMed = (100.f + float(params->colorToning.redmed)) / 100.f; - float GreenMed = (100.f + float(params->colorToning.greenmed)) / 100.f; - float BlueMed = (100.f + float(params->colorToning.bluemed)) / 100.f; - float RedHigh = (100.f + float(params->colorToning.redhigh)) / 100.f; //printf("RedH=%f\n",RedHigh); - float GreenHigh = (100.f + float(params->colorToning.greenhigh)) / 100.f; - float BlueHigh = (100.f + float(params->colorToning.bluehigh)) / 100.f; - float SatLow = float(params->colorToning.shadowsColSat.value[0]) / 100.f; - float SatHigh = float(params->colorToning.hlColSat.value[0]) / 100.f; + float RedLow = (100.f + float (params->colorToning.redlow)) / 100.f; //printf("Rel=%f\n",RedLow); + float GreenLow = (100.f + float (params->colorToning.greenlow)) / 100.f; //printf("Gre=%f\n",GreenLow); + float BlueLow = (100.f + float (params->colorToning.bluelow)) / 100.f; //printf("Blu=%f\n",BlueLow); + float RedMed = (100.f + float (params->colorToning.redmed)) / 100.f; + float GreenMed = (100.f + float (params->colorToning.greenmed)) / 100.f; + float BlueMed = (100.f + float (params->colorToning.bluemed)) / 100.f; + float RedHigh = (100.f + float (params->colorToning.redhigh)) / 100.f; //printf("RedH=%f\n",RedHigh); + float GreenHigh = (100.f + float (params->colorToning.greenhigh)) / 100.f; + float BlueHigh = (100.f + float (params->colorToning.bluehigh)) / 100.f; + float SatLow = float (params->colorToning.shadowsColSat.value[0]) / 100.f; + float SatHigh = float (params->colorToning.hlColSat.value[0]) / 100.f; - float Balan = float(params->colorToning.balance); + float Balan = float (params->colorToning.balance); - float chMixRR = float(params->chmixer.red[0]); - float chMixRG = float(params->chmixer.red[1]); - float chMixRB = float(params->chmixer.red[2]); - float chMixGR = float(params->chmixer.green[0]); - float chMixGG = float(params->chmixer.green[1]); - float chMixGB = float(params->chmixer.green[2]); - float chMixBR = float(params->chmixer.blue[0]); - float chMixBG = float(params->chmixer.blue[1]); - float chMixBB = float(params->chmixer.blue[2]); + float chMixRR = float (params->chmixer.red[0]); + float chMixRG = float (params->chmixer.red[1]); + float chMixRB = float (params->chmixer.red[2]); + float chMixGR = float (params->chmixer.green[0]); + float chMixGG = float (params->chmixer.green[1]); + float chMixGB = float (params->chmixer.green[2]); + float chMixBR = float (params->chmixer.blue[0]); + float chMixBG = float (params->chmixer.blue[1]); + float chMixBB = float (params->chmixer.blue[2]); int shHighlights = params->sh.highlights; int shShadows = params->sh.shadows; bool blackwhite = params->blackwhite.enabled; bool complem = params->blackwhite.enabledcc; - float bwr = float(params->blackwhite.mixerRed); - float bwg = float(params->blackwhite.mixerGreen); - float bwb = float(params->blackwhite.mixerBlue); - float bwrgam = float(params->blackwhite.gammaRed); - float bwggam = float(params->blackwhite.gammaGreen); - float bwbgam = float(params->blackwhite.gammaBlue); - float mixerOrange = float(params->blackwhite.mixerOrange); - float mixerYellow = float(params->blackwhite.mixerYellow); - float mixerCyan = float(params->blackwhite.mixerCyan); - float mixerMagenta = float(params->blackwhite.mixerMagenta); - float mixerPurple = float(params->blackwhite.mixerPurple); + float bwr = float (params->blackwhite.mixerRed); + float bwg = float (params->blackwhite.mixerGreen); + float bwb = float (params->blackwhite.mixerBlue); + float bwrgam = float (params->blackwhite.gammaRed); + float bwggam = float (params->blackwhite.gammaGreen); + float bwbgam = float (params->blackwhite.gammaBlue); + float mixerOrange = float (params->blackwhite.mixerOrange); + float mixerYellow = float (params->blackwhite.mixerYellow); + float mixerCyan = float (params->blackwhite.mixerCyan); + float mixerMagenta = float (params->blackwhite.mixerMagenta); + float mixerPurple = float (params->blackwhite.mixerPurple); int algm = 0; if (params->blackwhite.method == "Desaturation") { algm = 0; - } else if(params->blackwhite.method == "LumEqualizer") { + } else if (params->blackwhite.method == "LumEqualizer") { algm = 1; - } else if(params->blackwhite.method == "ChannelMixer") { + } else if (params->blackwhite.method == "ChannelMixer") { algm = 2; } @@ -3217,15 +3233,15 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float gamvalb = 125.f; bool computeMixerAuto = params->blackwhite.autoc && (autor < -5000.f); - if(bwrgam < 0) { + if (bwrgam < 0) { gamvalr = 100.f; } - if(bwggam < 0) { + if (bwggam < 0) { gamvalg = 100.f; } - if(bwbgam < 0) { + if (bwbgam < 0) { gamvalb = 100.f; } @@ -3241,20 +3257,20 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer bool hasgammabw = gammabwr != 1.f || gammabwg != 1.f || gammabwb != 1.f; if (hasColorToning || blackwhite || (params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled)) { - tmpImage = new Imagefloat(working->getWidth(), working->getHeight()); + tmpImage = new Imagefloat (working->getWidth(), working->getHeight()); } // For tonecurve histogram int toneCurveHistSize = histToneCurve ? histToneCurve.getSize() : 0; int histToneCurveCompression = 0; - if(toneCurveHistSize > 0) { + if (toneCurveHistSize > 0) { histToneCurve.clear(); - histToneCurveCompression = log2(65536 / toneCurveHistSize); + histToneCurveCompression = log2 (65536 / toneCurveHistSize); } // For tonecurve histogram - const float lumimulf[3] = {static_cast<float>(lumimul[0]), static_cast<float>(lumimul[1]), static_cast<float>(lumimul[2])}; + const float lumimulf[3] = {static_cast<float> (lumimul[0]), static_cast<float> (lumimul[1]), static_cast<float> (lumimul[2])}; #define TS 112 @@ -3267,13 +3283,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer char *editIFloatBuffer = nullptr; char *editWhateverBuffer = nullptr; - buffer = (char *) malloc(3 * sizeof(float) * TS * TS + 20 * 64 + 63); + buffer = (char *) malloc (3 * sizeof (float) * TS * TS + 20 * 64 + 63); char *data; - data = (char*)( ( uintptr_t(buffer) + uintptr_t(63)) / 64 * 64); + data = (char*) ( ( uintptr_t (buffer) + uintptr_t (63)) / 64 * 64); - float *rtemp = (float(*))data; - float *gtemp = (float (*)) ((char*)rtemp + sizeof(float) * TS * TS + 4 * 64); - float *btemp = (float (*)) ((char*)gtemp + sizeof(float) * TS * TS + 8 * 64); + float *rtemp = (float (*))data; + float *gtemp = (float (*)) ((char*)rtemp + sizeof (float) * TS * TS + 4 * 64); + float *btemp = (float (*)) ((char*)gtemp + sizeof (float) * TS * TS + 8 * 64); int istart; int jstart; int tW; @@ -3283,26 +3299,27 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float *editIFloatTmpR = nullptr, *editIFloatTmpG = nullptr, *editIFloatTmpB = nullptr, *editWhateverTmp = nullptr; if (editImgFloat) { - editIFloatBuffer = (char *) malloc(3 * sizeof(float) * TS * TS + 20 * 64 + 63); - data = (char*)( ( uintptr_t(editIFloatBuffer) + uintptr_t(63)) / 64 * 64); + editIFloatBuffer = (char *) malloc (3 * sizeof (float) * TS * TS + 20 * 64 + 63); + data = (char*) ( ( uintptr_t (editIFloatBuffer) + uintptr_t (63)) / 64 * 64); - editIFloatTmpR = (float(*))data; - editIFloatTmpG = (float (*)) ((char*)editIFloatTmpR + sizeof(float) * TS * TS + 4 * 64); - editIFloatTmpB = (float (*)) ((char*)editIFloatTmpG + sizeof(float) * TS * TS + 8 * 64); + editIFloatTmpR = (float (*))data; + editIFloatTmpG = (float (*)) ((char*)editIFloatTmpR + sizeof (float) * TS * TS + 4 * 64); + editIFloatTmpB = (float (*)) ((char*)editIFloatTmpG + sizeof (float) * TS * TS + 8 * 64); } if (editWhatever) { - editWhateverBuffer = (char *) malloc(sizeof(float) * TS * TS + 20 * 64 + 63); - data = (char*)( ( uintptr_t(editWhateverBuffer) + uintptr_t(63)) / 64 * 64); + editWhateverBuffer = (char *) malloc (sizeof (float) * TS * TS + 20 * 64 + 63); + data = (char*) ( ( uintptr_t (editWhateverBuffer) + uintptr_t (63)) / 64 * 64); - editWhateverTmp = (float(*))data; + editWhateverTmp = (float (*))data; } float out_rgbx[4 * TS] ALIGNED16; // Line buffer for CLUT LUTu histToneCurveThr; - if(toneCurveHistSize > 0) { - histToneCurveThr(toneCurveHistSize); + + if (toneCurveHistSize > 0) { + histToneCurveThr (toneCurveHistSize); histToneCurveThr.clear(); } @@ -3310,19 +3327,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #pragma omp for schedule(dynamic) collapse(2) #endif - for(int ii = 0; ii < working->getHeight(); ii += TS) - for(int jj = 0; jj < working->getWidth(); jj += TS) { + for (int ii = 0; ii < working->getHeight(); ii += TS) + for (int jj = 0; jj < working->getWidth(); jj += TS) { istart = ii; jstart = jj; - tH = min(ii + TS, working->getHeight()); - tW = min(jj + TS, working->getWidth()); + tH = min (ii + TS, working->getHeight()); + tW = min (jj + TS, working->getWidth()); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - rtemp[ti * TS + tj] = working->r(i, j); - gtemp[ti * TS + tj] = working->g(i, j); - btemp[ti * TS + tj] = working->b(i, j); + rtemp[ti * TS + tj] = working->r (i, j); + gtemp[ti * TS + tj] = working->g (i, j); + btemp[ti * TS + tj] = working->b (i, j); } } @@ -3415,7 +3432,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (dcpProf) { - dcpProf->step2ApplyTile(rtemp, gtemp, btemp, tW - jstart, tH - istart, TS, asIn); + dcpProf->step2ApplyTile (rtemp, gtemp, btemp, tW - jstart, tH - istart, TS, asIn); } for (int i = istart, ti = 0; i < tH; i++, ti++) { @@ -3438,7 +3455,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (r > 65535 || g > 65535 || b > 65535) { - filmlike_clip(&r, &g, &b); + filmlike_clip (&r, &g, &b); } rtemp[ti * TS + tj] = r; @@ -3454,9 +3471,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer rtemp[ti * TS + tj] = tonecurve[ rtemp[ti * TS + tj] ]; gtemp[ti * TS + tj] = tonecurve[ gtemp[ti * TS + tj] ]; btemp[ti * TS + tj] = tonecurve[ btemp[ti * TS + tj] ]; - if(histToneCurveThr) { - int y = CLIP<int>(lumimulf[0] * Color::gamma2curve[rtemp[ti * TS + tj]] + lumimulf[1] * Color::gamma2curve[gtemp[ti * TS + tj]] + lumimulf[2] * Color::gamma2curve[btemp[ti * TS + tj]]); - histToneCurveThr[y>>histToneCurveCompression]++; + + if (histToneCurveThr) { + int y = CLIP<int> (lumimulf[0] * Color::gamma2curve[rtemp[ti * TS + tj]] + lumimulf[1] * Color::gamma2curve[gtemp[ti * TS + tj]] + lumimulf[2] * Color::gamma2curve[btemp[ti * TS + tj]]); + histToneCurveThr[y >> histToneCurveCompression]++; } } } @@ -3475,58 +3493,58 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (curveMode == ToneCurveParams::TC_MODE_STD) { // Standard for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const StandardToneCurve& userToneCurve = static_cast<const StandardToneCurve&>(customToneCurve1); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const StandardToneCurve& userToneCurve = static_cast<const StandardToneCurve&> (customToneCurve1); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode == ToneCurveParams::TC_MODE_FILMLIKE) { // Adobe like for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const AdobeToneCurve& userToneCurve = static_cast<const AdobeToneCurve&>(customToneCurve1); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const AdobeToneCurve& userToneCurve = static_cast<const AdobeToneCurve&> (customToneCurve1); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode == ToneCurveParams::TC_MODE_SATANDVALBLENDING) { // apply the curve on the saturation and value channels for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const SatAndValueBlendingToneCurve& userToneCurve = static_cast<const SatAndValueBlendingToneCurve&>(customToneCurve1); - rtemp[ti * TS + tj] = CLIP<float>(rtemp[ti * TS + tj]); - gtemp[ti * TS + tj] = CLIP<float>(gtemp[ti * TS + tj]); - btemp[ti * TS + tj] = CLIP<float>(btemp[ti * TS + tj]); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const SatAndValueBlendingToneCurve& userToneCurve = static_cast<const SatAndValueBlendingToneCurve&> (customToneCurve1); + rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]); + gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]); + btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode == ToneCurveParams::TC_MODE_WEIGHTEDSTD) { // apply the curve to the rgb channels, weighted - const WeightedStdToneCurve& userToneCurve = static_cast<const WeightedStdToneCurve&>(customToneCurve1); + const WeightedStdToneCurve& userToneCurve = static_cast<const WeightedStdToneCurve&> (customToneCurve1); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - rtemp[ti * TS + tj] = CLIP<float>(rtemp[ti * TS + tj]); - gtemp[ti * TS + tj] = CLIP<float>(gtemp[ti * TS + tj]); - btemp[ti * TS + tj] = CLIP<float>(btemp[ti * TS + tj]); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]); + gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]); + btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode == ToneCurveParams::TC_MODE_LUMINANCE) { // apply the curve to the luminance channel - const LuminanceToneCurve& userToneCurve = static_cast<const LuminanceToneCurve&>(customToneCurve1); + const LuminanceToneCurve& userToneCurve = static_cast<const LuminanceToneCurve&> (customToneCurve1); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - rtemp[ti * TS + tj] = CLIP<float>(rtemp[ti * TS + tj]); - gtemp[ti * TS + tj] = CLIP<float>(gtemp[ti * TS + tj]); - btemp[ti * TS + tj] = CLIP<float>(btemp[ti * TS + tj]); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]); + gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]); + btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode == ToneCurveParams::TC_MODE_PERCEPTUAL) { // apply curve while keeping color appearance constant - const PerceptualToneCurve& userToneCurve = static_cast<const PerceptualToneCurve&>(customToneCurve1); + const PerceptualToneCurve& userToneCurve = static_cast<const PerceptualToneCurve&> (customToneCurve1); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - rtemp[ti * TS + tj] = CLIP<float>(rtemp[ti * TS + tj]); - gtemp[ti * TS + tj] = CLIP<float>(gtemp[ti * TS + tj]); - btemp[ti * TS + tj] = CLIP<float>(btemp[ti * TS + tj]); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], ptc1ApplyState); + rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]); + gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]); + btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], ptc1ApplyState); } } } @@ -3546,46 +3564,46 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (curveMode2 == ToneCurveParams::TC_MODE_STD) { // Standard for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const StandardToneCurve& userToneCurve = static_cast<const StandardToneCurve&>(customToneCurve2); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const StandardToneCurve& userToneCurve = static_cast<const StandardToneCurve&> (customToneCurve2); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode2 == ToneCurveParams::TC_MODE_FILMLIKE) { // Adobe like for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const AdobeToneCurve& userToneCurve = static_cast<const AdobeToneCurve&>(customToneCurve2); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const AdobeToneCurve& userToneCurve = static_cast<const AdobeToneCurve&> (customToneCurve2); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode2 == ToneCurveParams::TC_MODE_SATANDVALBLENDING) { // apply the curve on the saturation and value channels for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const SatAndValueBlendingToneCurve& userToneCurve = static_cast<const SatAndValueBlendingToneCurve&>(customToneCurve2); - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const SatAndValueBlendingToneCurve& userToneCurve = static_cast<const SatAndValueBlendingToneCurve&> (customToneCurve2); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode2 == ToneCurveParams::TC_MODE_WEIGHTEDSTD) { // apply the curve to the rgb channels, weighted - const WeightedStdToneCurve& userToneCurve = static_cast<const WeightedStdToneCurve&>(customToneCurve2); + const WeightedStdToneCurve& userToneCurve = static_cast<const WeightedStdToneCurve&> (customToneCurve2); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode2 == ToneCurveParams::TC_MODE_LUMINANCE) { // apply the curve to the luminance channel - const LuminanceToneCurve& userToneCurve = static_cast<const LuminanceToneCurve&>(customToneCurve2); + const LuminanceToneCurve& userToneCurve = static_cast<const LuminanceToneCurve&> (customToneCurve2); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (curveMode2 == ToneCurveParams::TC_MODE_PERCEPTUAL) { // apply curve while keeping color appearance constant - const PerceptualToneCurve& userToneCurve = static_cast<const PerceptualToneCurve&>(customToneCurve2); + const PerceptualToneCurve& userToneCurve = static_cast<const PerceptualToneCurve&> (customToneCurve2); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - userToneCurve.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], ptc2ApplyState); + userToneCurve.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], ptc2ApplyState); } } } @@ -3646,9 +3664,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float y = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; float z = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b; - float fx = x < MAXVALF ? Color::cachef[x] : 327.68f * std::cbrt(x / MAXVALF); - float fy = y < MAXVALF ? Color::cachef[y] : 327.68f * std::cbrt(y / MAXVALF); - float fz = z < MAXVALF ? Color::cachef[z] : 327.68f * std::cbrt(z / MAXVALF); + float fx = x < MAXVALF ? Color::cachef[x] : 327.68f * std::cbrt (x / MAXVALF); + float fy = y < MAXVALF ? Color::cachef[y] : 327.68f * std::cbrt (y / MAXVALF); + float fz = z < MAXVALF ? Color::cachef[z] : 327.68f * std::cbrt (z / MAXVALF); float a_1 = 500.0f * (fx - fy); float b_1 = 200.0f * (fy - fz); @@ -3672,19 +3690,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // Luminosity after // only Luminance in Lab float newy = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; - float newfy = newy < MAXVALF ? Color::cachef[newy] : 327.68f * std::cbrt(newy / MAXVALF); + float newfy = newy < MAXVALF ? Color::cachef[newy] : 327.68f * std::cbrt (newy / MAXVALF); float L_2 = 116.0f * newfy - 5242.88f; //gamut control - if(settings->rgbcurveslumamode_gamut) { + if (settings->rgbcurveslumamode_gamut) { float Lpro = L_2 / 327.68f; - float Chpro = sqrtf(SQR(a_1) + SQR(b_1)) / 327.68f; + float Chpro = sqrtf (SQR (a_1) + SQR (b_1)) / 327.68f; float HH = NAN; // we set HH to NAN, because then it will be calculated in Color::gamutLchonly only if needed // float HH = xatan2f(b_1, a_1); // According to mathematical laws we can get the sin and cos of HH by simple operations even if we don't calculate HH float2 sincosval; - if(Chpro == 0.0f) { + if (Chpro == 0.0f) { sincosval.y = 1.0f; sincosval.x = 0.0f; } else { @@ -3696,17 +3714,17 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lpro, Chpro, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (HH, sincosval, Lpro, Chpro, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lpro, Chpro, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly (HH, sincosval, Lpro, Chpro, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip, highlight, 0.15f, 0.96f); #endif - //end of gamut control + //end of gamut control } else { float x_, y_, z_; //calculate RGB with L_2 and old value of a and b - Color::Lab2XYZ(L_2, a_1, b_1, x_, y_, z_) ; - Color::xyz2rgb(x_, y_, z_, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip); + Color::Lab2XYZ (L_2, a_1, b_1, x_, y_, z_) ; + Color::xyz2rgb (x_, y_, z_, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip); } } } @@ -3717,7 +3735,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { float h, s, v; - Color::rgb2hsv(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], h, s, v); + Color::rgb2hsv (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], h, s, v); editWhateverTmp[ti * TS + tj] = h; } } @@ -3732,10 +3750,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float g = gtemp[ti * TS + tj]; float b = btemp[ti * TS + tj]; float h, s, v; - Color::rgb2hsv(r, g, b, h, s, v); + Color::rgb2hsv (r, g, b, h, s, v); if (sat > 0) { - s = (1.f - satby100) * s + satby100 * (1.f - SQR(SQR(1.f - min(s, 1.0f)))); + s = (1.f - satby100) * s + satby100 * (1.f - SQR (SQR (1.f - min (s, 1.0f)))); if (s < 0.f) { s = 0.f; @@ -3746,7 +3764,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer //HSV equalizer if (hCurveEnabled) { - h = (hCurve->getVal(double(h)) - 0.5) * 2.f + h; + h = (hCurve->getVal (double (h)) - 0.5) * 2.f + h; if (h > 1.0f) { h -= 1.0f; @@ -3757,10 +3775,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (sCurveEnabled) { //shift saturation - float satparam = (sCurve->getVal(double(h)) - 0.5) * 2; + float satparam = (sCurve->getVal (double (h)) - 0.5) * 2; if (satparam > 0.00001f) { - s = (1.f - satparam) * s + satparam * (1.f - SQR(1.f - min(s, 1.0f))); + s = (1.f - satparam) * s + satparam * (1.f - SQR (1.f - min (s, 1.0f))); if (s < 0.f) { s = 0.f; @@ -3777,11 +3795,11 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } //shift value - float valparam = vCurve->getVal((double)h) - 0.5f; - valparam *= (1.f - SQR(SQR(1.f - min(s, 1.0f)))); + float valparam = vCurve->getVal ((double)h) - 0.5f; + valparam *= (1.f - SQR (SQR (1.f - min (s, 1.0f)))); if (valparam > 0.00001f) { - v = (1.f - valparam) * v + valparam * (1.f - SQR(1.f - min(v, 1.0f))); // SQR (SQR to increase action and avoid artefacts + v = (1.f - valparam) * v + valparam * (1.f - SQR (1.f - min (v, 1.0f))); // SQR (SQR to increase action and avoid artefacts if (v < 0) { v = 0; @@ -3794,7 +3812,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } - Color::hsv2rgb(h, s, v, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + Color::hsv2rgb (h, s, v, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } @@ -3805,12 +3823,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float r = rtemp[ti * TS + tj]; float g = gtemp[ti * TS + tj]; - if(r == 0.0f || g == 0.0f) { + if (r == 0.0f || g == 0.0f) { float b = btemp[ti * TS + tj]; float h, s, v; - Color::rgb2hsv(r, g, b, h, s, v); + Color::rgb2hsv (r, g, b, h, s, v); s *= 0.99f; - Color::hsv2rgb(h, s, v, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + Color::hsv2rgb (h, s, v, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } @@ -3822,7 +3840,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float reducac = 0.4f; int preser = 0; - if(params->colorToning.lumamode) { + if (params->colorToning.lumamode) { preser = 1; } @@ -3836,14 +3854,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer iplow = (float)ctColorCurve.low; iphigh = (float)ctColorCurve.high; //2 colours - ctColorCurve.getVal(iphigh, xh, yh, zh); - ctColorCurve.getVal(iplow, xl, yl, zl); + ctColorCurve.getVal (iphigh, xh, yh, zh); + ctColorCurve.getVal (iplow, xl, yl, zl); - Color::xyz2rgb(xh, yh, zh, rh, gh, bh, wip); - Color::xyz2rgb(xl, yl, zl, rl, gl, bl, wip); + Color::xyz2rgb (xh, yh, zh, rh, gh, bh, wip); + Color::xyz2rgb (xl, yl, zl, rl, gl, bl, wip); //reteave rgb value with s and l =1 - retreavergb(rl, gl, bl); - retreavergb(rh, gh, bh); + retreavergb (rl, gl, bl); + retreavergb (rh, gh, bh); //printf("rl=%f gl=%f bl=%f\n",rl,gl,bl); for (int i = istart, ti = 0; i < tH; i++, ti++) { @@ -3883,7 +3901,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int preser = 0; //bool execbal = params->colorToning.method=="Splitbal"; - if(params->colorToning.lumamode) { + if (params->colorToning.lumamode) { preser = 1; } @@ -3899,16 +3917,16 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float lumafter = 0.299f * ro + 0.587f * go + 0.114f * bo; float preserv = 1.f; - if(preser == 1) { + if (preser == 1) { preserv = lumbefore / lumafter; } ro *= preserv; go *= preserv; bo *= preserv; - ro = CLIP(ro); - go = CLIP(go); - bo = CLIP(bo); + ro = CLIP (ro); + go = CLIP (go); + bo = CLIP (bo); rtemp[ti * TS + tj] = ro; gtemp[ti * TS + tj] = go; btemp[ti * TS + tj] = bo; @@ -3934,13 +3952,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer metchrom = 3; } - if(metchrom == 3) { + if (metchrom == 3) { twocol = false; } float iplow = 0.f, iphigh = 0.f; - if(!twocol) { + if (!twocol) { iplow = (float)ctColorCurve.low; iphigh = (float)ctColorCurve.high; } @@ -3967,13 +3985,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float b = btemp[ti * TS + tj]; float ro, go, bo; labtoning (r, g, b, ro, go, bo, algm, metchrom, twoc, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, clToningcurve, cl2Toningcurve, iplow, iphigh, wp, wip); - rtemp[ti * TS + tj] = CLIP(ro); //I used CLIP because there is a little bug in gamutLchonly that return 65536.ii intead of 65535 ==> crash - gtemp[ti * TS + tj] = CLIP(go); - btemp[ti * TS + tj] = CLIP(bo); + rtemp[ti * TS + tj] = CLIP (ro); //I used CLIP because there is a little bug in gamutLchonly that return 65536.ii intead of 65535 ==> crash + gtemp[ti * TS + tj] = CLIP (go); + btemp[ti * TS + tj] = CLIP (bo); } } } - } else if (params->colorToning.method.substr(0, 3) == "RGB" && opautili) { + } else if (params->colorToning.method.substr (0, 3) == "RGB" && opautili) { // color toning for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { @@ -3984,28 +4002,28 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // Luminance = (0.299f*r + 0.587f*g + 0.114f*b) float h, s, l; - Color::rgb2hsl(r, g, b, h, s, l); + Color::rgb2hsl (r, g, b, h, s, l); - float l_ = Color::gamma_srgb(l * 65535.f) / 65535.f; + float l_ = Color::gamma_srgb (l * 65535.f) / 65535.f; // get the opacity and tweak it to preserve saturated colors float opacity; - if(ctOpacityCurve) { - opacity = (1.f - min<float>(s / satLimit, 1.f) * (1.f - satLimitOpacity)) * ctOpacityCurve.lutOpacityCurve[l_ * 500.f]; + if (ctOpacityCurve) { + opacity = (1.f - min<float> (s / satLimit, 1.f) * (1.f - satLimitOpacity)) * ctOpacityCurve.lutOpacityCurve[l_ * 500.f]; } - if(!ctOpacityCurve) { + if (!ctOpacityCurve) { opacity = 0.f; } float r2, g2, b2; - ctColorCurve.getVal(l_, r2, g2, b2); // get the color from the color curve + ctColorCurve.getVal (l_, r2, g2, b2); // get the color from the color curve float h2, s2, l2; - Color::rgb2hsl(r2, g2, b2, h2, s2, l2); // transform this new color to hsl + Color::rgb2hsl (r2, g2, b2, h2, s2, l2); // transform this new color to hsl - Color::hsl2rgb(h2, s + ((1.f - s) * (1.f - l) * 0.7f), l, r2, g2, b2); + Color::hsl2rgb (h2, s + ((1.f - s) * (1.f - l) * 0.7f), l, r2, g2, b2); rtemp[ti * TS + tj] = r + (r2 - r) * opacity; // merge the color to the old color, depending on the opacity gtemp[ti * TS + tj] = g + (g2 - g) * opacity; @@ -4029,53 +4047,53 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int j = jstart, tj = 0; j < tW; j++, tj++) { float X, Y, Z, L, aa, bb; //rgb=>lab - Color::rgbxyz(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], X, Y, Z, wp); + Color::rgbxyz (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], X, Y, Z, wp); //convert Lab - Color::XYZ2Lab(X, Y, Z, L, aa, bb); + Color::XYZ2Lab (X, Y, Z, L, aa, bb); //end rgb=>lab - float HH = xatan2f(bb, aa); // HH hue in -3.141 +3.141 + float HH = xatan2f (bb, aa); // HH hue in -3.141 +3.141 - editWhateverTmp[ti * TS + tj] = float(Color::huelab_to_huehsv2(HH)); + editWhateverTmp[ti * TS + tj] = float (Color::huelab_to_huehsv2 (HH)); } } } //black and white - if(blackwhite) { + if (blackwhite) { if (hasToneCurvebw1) { if (beforeCurveMode == BlackWhiteParams::TC_MODE_STD_BW) { // Standard for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const StandardToneCurvebw& userToneCurvebw = static_cast<const StandardToneCurvebw&>(customToneCurvebw1); - userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const StandardToneCurvebw& userToneCurvebw = static_cast<const StandardToneCurvebw&> (customToneCurvebw1); + userToneCurvebw.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (beforeCurveMode == BlackWhiteParams::TC_MODE_FILMLIKE_BW) { // Adobe like for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const AdobeToneCurvebw& userToneCurvebw = static_cast<const AdobeToneCurvebw&>(customToneCurvebw1); - userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const AdobeToneCurvebw& userToneCurvebw = static_cast<const AdobeToneCurvebw&> (customToneCurvebw1); + userToneCurvebw.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (beforeCurveMode == BlackWhiteParams::TC_MODE_SATANDVALBLENDING_BW) { // apply the curve on the saturation and value channels for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const SatAndValueBlendingToneCurvebw& userToneCurvebw = static_cast<const SatAndValueBlendingToneCurvebw&>(customToneCurvebw1); - rtemp[ti * TS + tj] = CLIP<float>(rtemp[ti * TS + tj]); - gtemp[ti * TS + tj] = CLIP<float>(gtemp[ti * TS + tj]); - btemp[ti * TS + tj] = CLIP<float>(btemp[ti * TS + tj]); - userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const SatAndValueBlendingToneCurvebw& userToneCurvebw = static_cast<const SatAndValueBlendingToneCurvebw&> (customToneCurvebw1); + rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]); + gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]); + btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]); + userToneCurvebw.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (beforeCurveMode == BlackWhiteParams::TC_MODE_WEIGHTEDSTD_BW) { // apply the curve to the rgb channels, weighted for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const WeightedStdToneCurvebw& userToneCurvebw = static_cast<const WeightedStdToneCurvebw&>(customToneCurvebw1); - rtemp[ti * TS + tj] = CLIP<float>(rtemp[ti * TS + tj]); - gtemp[ti * TS + tj] = CLIP<float>(gtemp[ti * TS + tj]); - btemp[ti * TS + tj] = CLIP<float>(btemp[ti * TS + tj]); + const WeightedStdToneCurvebw& userToneCurvebw = static_cast<const WeightedStdToneCurvebw&> (customToneCurvebw1); + rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]); + gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]); + btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]); - userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + userToneCurvebw.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } @@ -4104,20 +4122,25 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // -------------------------------------------------- #ifndef __SSE2__ + //gamma correction: pseudo TRC curve if (hasgammabw) { Color::trcGammaBW (r, g, b, gammabwr, gammabwg, gammabwb); } + #endif rtemp[ti * TS + tj] = r; gtemp[ti * TS + tj] = g; btemp[ti * TS + tj] = b; } + #ifdef __SSE2__ + if (hasgammabw) { //gamma correction: pseudo TRC curve Color::trcGammaBWRow (&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], tW - jstart, gammabwr, gammabwg, gammabwb); } + #endif } @@ -4126,15 +4149,15 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int j = jstart, tj = 0; j < tW; j++, tj++) { //rgb => xyz float X, Y, Z; - Color::rgbxyz(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], X, Y, Z, wp); + Color::rgbxyz (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], X, Y, Z, wp); //xyz => Lab float L, aa, bb; - Color::XYZ2Lab(X, Y, Z, L, aa, bb); - float CC = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; //CC chromaticity in 0..180 or more - float HH = xatan2f(bb, aa); // HH hue in -3.141 +3.141 + Color::XYZ2Lab (X, Y, Z, L, aa, bb); + float CC = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; //CC chromaticity in 0..180 or more + float HH = xatan2f (bb, aa); // HH hue in -3.141 +3.141 float2 sincosval; - if(CC == 0.0f) { + if (CC == 0.0f) { sincosval.y = 1.f; sincosval.x = 0.0f; } else { @@ -4144,17 +4167,18 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (bwlCurveEnabled) { L /= 32768.f; - double hr = Color::huelab_to_huehsv2(HH); - float valparam = float((bwlCurve->getVal(hr) - 0.5f) * 2.0f); //get l_r=f(H) + double hr = Color::huelab_to_huehsv2 (HH); + float valparam = float ((bwlCurve->getVal (hr) - 0.5f) * 2.0f); //get l_r=f(H) float kcc = (CC / 70.f); //take Chroma into account...70 "middle" of chromaticity (arbitrary and simple), one can imagine other algorithme //reduct action for low chroma and increase action for high chroma valparam *= kcc; - if(valparam > 0.f) { - L = (1.f - valparam) * L + valparam * (1.f - SQR(SQR(SQR(SQR(1.f - min(L, 1.0f)))))); // SQR (SQR((SQR) to increase action in low light + if (valparam > 0.f) { + L = (1.f - valparam) * L + valparam * (1.f - SQR (SQR (SQR (SQR (1.f - min (L, 1.0f)))))); // SQR (SQR((SQR) to increase action in low light } else { L *= (1.f + valparam); //for negative } + L *= 32768.f; } @@ -4164,29 +4188,34 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, L, CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (HH, sincosval, L, CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, L, CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly (HH, sincosval, L, CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f); #endif L *= 327.68f; //convert l => rgb - Color::L2XYZ(L, X, Y, Z); + Color::L2XYZ (L, X, Y, Z); float newRed; // We use the red channel for bw - Color::xyz2r(X, Y, Z, newRed, wip); + Color::xyz2r (X, Y, Z, newRed, wip); rtemp[ti * TS + tj] = gtemp[ti * TS + tj] = btemp[ti * TS + tj] = newRed; #ifndef __SSE2__ + if (hasgammabw) { //gamma correction: pseudo TRC curve Color::trcGammaBW (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], gammabwr, gammabwg, gammabwb); } + #endif } + #ifdef __SSE2__ + if (hasgammabw) { //gamma correction: pseudo TRC curve Color::trcGammaBWRow (&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], tW - jstart, gammabwr, gammabwg, gammabwb); } + #endif } } @@ -4205,19 +4234,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #ifdef __SSE2__ for (; j < tW - 3; j += 4, tj += 4) { - vfloat sourceR = LVF(rtemp[ti * TS + tj]); - vfloat sourceG = LVF(gtemp[ti * TS + tj]); - vfloat sourceB = LVF(btemp[ti * TS + tj]); + vfloat sourceR = LVF (rtemp[ti * TS + tj]); + vfloat sourceG = LVF (gtemp[ti * TS + tj]); + vfloat sourceB = LVF (btemp[ti * TS + tj]); vfloat x; vfloat y; vfloat z; - Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, v_work2xyz); - Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, v_xyz2clut); + Color::rgbxyz (sourceR, sourceG, sourceB, x, y, z, v_work2xyz); + Color::xyz2rgb (x, y, z, sourceR, sourceG, sourceB, v_xyz2clut); - STVF(rtemp[ti * TS + tj], sourceR); - STVF(gtemp[ti * TS + tj], sourceG); - STVF(btemp[ti * TS + tj], sourceB); + STVF (rtemp[ti * TS + tj], sourceR); + STVF (gtemp[ti * TS + tj], sourceG); + STVF (btemp[ti * TS + tj], sourceB); } #endif @@ -4228,8 +4257,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float &sourceB = btemp[ti * TS + tj]; float x, y, z; - Color::rgbxyz( sourceR, sourceG, sourceB, x, y, z, wprof ); - Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, xyz2clut); + Color::rgbxyz ( sourceR, sourceG, sourceB, x, y, z, wprof ); + Color::xyz2rgb (x, y, z, sourceR, sourceG, sourceB, xyz2clut); } } @@ -4239,15 +4268,15 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float &sourceB = btemp[ti * TS + tj]; // Apply gamma sRGB (default RT) - sourceR = Color::gamma_srgbclipped(sourceR); - sourceG = Color::gamma_srgbclipped(sourceG); - sourceB = Color::gamma_srgbclipped(sourceB); + sourceR = Color::gamma_srgbclipped (sourceR); + sourceG = Color::gamma_srgbclipped (sourceG); + sourceB = Color::gamma_srgbclipped (sourceB); } const std::size_t line_offset = ti * TS; - hald_clut->getRGB( + hald_clut->getRGB ( film_simulation_strength, - std::min(TS, tW - jstart), + std::min (TS, tW - jstart), rtemp + line_offset, gtemp + line_offset, btemp + line_offset, @@ -4260,9 +4289,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float &sourceB = btemp[ti * TS + tj]; // Apply inverse gamma sRGB - sourceR = Color::igamma_srgb(out_rgbx[tj * 4 + 0]); - sourceG = Color::igamma_srgb(out_rgbx[tj * 4 + 1]); - sourceB = Color::igamma_srgb(out_rgbx[tj * 4 + 2]); + sourceR = Color::igamma_srgb (out_rgbx[tj * 4 + 0]); + sourceG = Color::igamma_srgb (out_rgbx[tj * 4 + 1]); + sourceB = Color::igamma_srgb (out_rgbx[tj * 4 + 2]); } if (!clutAndWorkingProfilesAreSame) { @@ -4273,19 +4302,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #ifdef __SSE2__ for (; j < tW - 3; j += 4, tj += 4) { - vfloat sourceR = LVF(rtemp[ti * TS + tj]); - vfloat sourceG = LVF(gtemp[ti * TS + tj]); - vfloat sourceB = LVF(btemp[ti * TS + tj]); + vfloat sourceR = LVF (rtemp[ti * TS + tj]); + vfloat sourceG = LVF (gtemp[ti * TS + tj]); + vfloat sourceB = LVF (btemp[ti * TS + tj]); vfloat x; vfloat y; vfloat z; - Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, v_clut2xyz); - Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, v_xyz2work); + Color::rgbxyz (sourceR, sourceG, sourceB, x, y, z, v_clut2xyz); + Color::xyz2rgb (x, y, z, sourceR, sourceG, sourceB, v_xyz2work); - STVF(rtemp[ti * TS + tj], sourceR); - STVF(gtemp[ti * TS + tj], sourceG); - STVF(btemp[ti * TS + tj], sourceB); + STVF (rtemp[ti * TS + tj], sourceR); + STVF (gtemp[ti * TS + tj], sourceG); + STVF (btemp[ti * TS + tj], sourceB); } #endif @@ -4296,8 +4325,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float &sourceB = btemp[ti * TS + tj]; float x, y, z; - Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, clut2xyz); - Color::xyz2rgb( x, y, z, sourceR, sourceG, sourceB, wiprof ); + Color::rgbxyz (sourceR, sourceG, sourceB, x, y, z, clut2xyz); + Color::xyz2rgb ( x, y, z, sourceR, sourceG, sourceB, wiprof ); } } } @@ -4311,11 +4340,11 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // filling the pipette buffer by the content of the temp pipette buffers if (editImgFloat) { - editImgFloat->r(i, j) = editIFloatTmpR[ti * TS + tj]; - editImgFloat->g(i, j) = editIFloatTmpG[ti * TS + tj]; - editImgFloat->b(i, j) = editIFloatTmpB[ti * TS + tj]; + editImgFloat->r (i, j) = editIFloatTmpR[ti * TS + tj]; + editImgFloat->g (i, j) = editIFloatTmpG[ti * TS + tj]; + editImgFloat->b (i, j) = editIFloatTmpB[ti * TS + tj]; } else if (editWhatever) { - editWhatever->v(i, j) = editWhateverTmp[ti * TS + tj]; + editWhatever->v (i, j) = editWhateverTmp[ti * TS + tj]; } float r = rtemp[ti * TS + tj]; @@ -4328,9 +4357,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float fx, fy, fz; - fx = (x < 65535.0f ? Color::cachef[x] : 327.68f * std::cbrt(x / MAXVALF)); - fy = (y < 65535.0f ? Color::cachef[y] : 327.68f * std::cbrt(y / MAXVALF)); - fz = (z < 65535.0f ? Color::cachef[z] : 327.68f * std::cbrt(z / MAXVALF)); + fx = (x < 65535.0f ? Color::cachef[x] : 327.68f * std::cbrt (x / MAXVALF)); + fy = (y < 65535.0f ? Color::cachef[y] : 327.68f * std::cbrt (y / MAXVALF)); + fz = (z < 65535.0f ? Color::cachef[z] : 327.68f * std::cbrt (z / MAXVALF)); lab->L[i][j] = (116.0f * fy - 5242.88f); //5242.88=16.0*327.68; lab->a[i][j] = (500.0f * (fx - fy) ); @@ -4359,22 +4388,22 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int j = jstart, tj = 0; j < tW; j++, tj++) { // filling the pipette buffer by the content of the temp pipette buffers if (editImgFloat) { - editImgFloat->r(i, j) = editIFloatTmpR[ti * TS + tj]; - editImgFloat->g(i, j) = editIFloatTmpG[ti * TS + tj]; - editImgFloat->b(i, j) = editIFloatTmpB[ti * TS + tj]; + editImgFloat->r (i, j) = editIFloatTmpR[ti * TS + tj]; + editImgFloat->g (i, j) = editIFloatTmpG[ti * TS + tj]; + editImgFloat->b (i, j) = editIFloatTmpB[ti * TS + tj]; } else if (editWhatever) { - editWhatever->v(i, j) = editWhateverTmp[ti * TS + tj]; + editWhatever->v (i, j) = editWhateverTmp[ti * TS + tj]; } - tmpImage->r(i, j) = rtemp[ti * TS + tj]; - tmpImage->g(i, j) = gtemp[ti * TS + tj]; - tmpImage->b(i, j) = btemp[ti * TS + tj]; + tmpImage->r (i, j) = rtemp[ti * TS + tj]; + tmpImage->g (i, j) = gtemp[ti * TS + tj]; + tmpImage->b (i, j) = btemp[ti * TS + tj]; } } } } - free(buffer); + free (buffer); if (editIFloatBuffer) { free (editIFloatBuffer); @@ -4383,13 +4412,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (editWhateverBuffer) { free (editWhateverBuffer); } + #ifdef _OPENMP -#pragma omp critical -{ - if(toneCurveHistSize > 0) { - histToneCurve += histToneCurveThr; - } -} + #pragma omp critical + { + if (toneCurveHistSize > 0) { + histToneCurve += histToneCurveThr; + } + } #endif // _OPENMP } @@ -4412,9 +4442,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - nr += tmpImage->r(i, j); - ng += tmpImage->g(i, j); - nb += tmpImage->b(i, j); + nr += tmpImage->r (i, j); + ng += tmpImage->g (i, j); + nb += tmpImage->b (i, j); } } @@ -4423,9 +4453,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer double kng = srgb / ng; double knb = srgb / nb; double sk = knr + kng + knb; - autor = (float)(100.0 * knr / sk); - autog = (float)(100.0 * kng / sk); - autob = (float)(100.0 * knb / sk); + autor = (float) (100.0 * knr / sk); + autog = (float) (100.0 * kng / sk); + autob = (float) (100.0 * knb / sk); } @@ -4442,9 +4472,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } float filcor; - Color::computeBWMixerConstants(params->blackwhite.setting, params->blackwhite.filter, params->blackwhite.algo, filcor, - bwr, bwg, bwb, mixerOrange, mixerYellow, mixerCyan, mixerPurple, mixerMagenta, - params->blackwhite.autoc, complem, kcorec, rrm, ggm, bbm); + Color::computeBWMixerConstants (params->blackwhite.setting, params->blackwhite.filter, params->blackwhite.algo, filcor, + bwr, bwg, bwb, mixerOrange, mixerYellow, mixerCyan, mixerPurple, mixerMagenta, + params->blackwhite.autoc, complem, kcorec, rrm, ggm, bbm); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 16) @@ -4454,20 +4484,25 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int j = 0; j < tW; j++) { //mix channel - tmpImage->r(i, j) = tmpImage->g(i, j) = tmpImage->b(i, j) = CLIP((bwr * tmpImage->r(i, j) + bwg * tmpImage->g(i, j) + bwb * tmpImage->b(i, j)) * kcorec); + tmpImage->r (i, j) = tmpImage->g (i, j) = tmpImage->b (i, j) = CLIP ((bwr * tmpImage->r (i, j) + bwg * tmpImage->g (i, j) + bwb * tmpImage->b (i, j)) * kcorec); #ifndef __SSE2__ + //gamma correction: pseudo TRC curve if (hasgammabw) { - Color::trcGammaBW (tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j), gammabwr, gammabwg, gammabwb); + Color::trcGammaBW (tmpImage->r (i, j), tmpImage->g (i, j), tmpImage->b (i, j), gammabwr, gammabwg, gammabwb); } + #endif } + #ifdef __SSE2__ + if (hasgammabw) { //gamma correction: pseudo TRC curve - Color::trcGammaBWRow (tmpImage->r(i), tmpImage->g(i), tmpImage->b(i), tW, gammabwr, gammabwg, gammabwb); + Color::trcGammaBWRow (tmpImage->r (i), tmpImage->g (i), tmpImage->b (i), tW, gammabwr, gammabwg, gammabwb); } + #endif } } @@ -4479,7 +4514,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - editWhatever->v(i, j) = Color::gamma2curve[tmpImage->r(i, j)] / 65535.f; // assuming that r=g=b + editWhatever->v (i, j) = Color::gamma2curve[tmpImage->r (i, j)] / 65535.f; // assuming that r=g=b } } } @@ -4493,8 +4528,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - const StandardToneCurvebw& userToneCurve = static_cast<const StandardToneCurvebw&>(customToneCurvebw2); - userToneCurve.Apply(tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j)); + const StandardToneCurvebw& userToneCurve = static_cast<const StandardToneCurvebw&> (customToneCurvebw2); + userToneCurve.Apply (tmpImage->r (i, j), tmpImage->g (i, j), tmpImage->b (i, j)); } } } else if (afterCurveMode == BlackWhiteParams::TC_MODE_WEIGHTEDSTD_BW) { // apply the curve to the rgb channels, weighted @@ -4504,13 +4539,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { //for ulterior usage if bw data modified for (int j = 0; j < tW; j++) { - const WeightedStdToneCurvebw& userToneCurve = static_cast<const WeightedStdToneCurvebw&>(customToneCurvebw2); + const WeightedStdToneCurvebw& userToneCurve = static_cast<const WeightedStdToneCurvebw&> (customToneCurvebw2); - tmpImage->r(i, j) = CLIP<float>(tmpImage->r(i, j)); - tmpImage->g(i, j) = CLIP<float>(tmpImage->g(i, j)); - tmpImage->b(i, j) = CLIP<float>(tmpImage->b(i, j)); + tmpImage->r (i, j) = CLIP<float> (tmpImage->r (i, j)); + tmpImage->g (i, j) = CLIP<float> (tmpImage->g (i, j)); + tmpImage->b (i, j) = CLIP<float> (tmpImage->b (i, j)); - userToneCurve.Apply(tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j)); + userToneCurve.Apply (tmpImage->r (i, j), tmpImage->g (i, j), tmpImage->b (i, j)); } } } @@ -4518,7 +4553,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer //colortoning with black and white if (hasColorToning) { - if(params->colorToning.method == "Splitco") { + if (params->colorToning.method == "Splitco") { /* #if 1 for (int i=istart,ti=0; i<tH; i++,ti++) { @@ -4537,7 +4572,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer */ int preser = 0; - if(params->colorToning.lumamode) { + if (params->colorToning.lumamode) { preser = 1; } @@ -4548,32 +4583,32 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float r = tmpImage->r(i, j); - float g = tmpImage->g(i, j); - float b = tmpImage->b(i, j); + float r = tmpImage->r (i, j); + float g = tmpImage->g (i, j); + float b = tmpImage->b (i, j); float lumbefore = 0.299f * r + 0.587f * g + 0.114f * b; - if(lumbefore < 65000.f && lumbefore > 500.f) { //reduct artifacts for highlights an extrem shadows + if (lumbefore < 65000.f && lumbefore > 500.f) { //reduct artifacts for highlights an extrem shadows float ro, go, bo; int mode = 1; toningsmh (r, g, b, ro, go, bo, RedLow, GreenLow, BlueLow, RedMed, GreenMed, BlueMed, RedHigh, GreenHigh, BlueHigh, reducac, mode, preser, strProtect); float lumafter = 0.299f * ro + 0.587f * go + 0.114f * bo; float preserv = 1.f; - if(preser == 1) { + if (preser == 1) { preserv = lumbefore / lumafter; } ro *= preserv; go *= preserv; bo *= preserv; - ro = CLIP(ro); - go = CLIP(go); - bo = CLIP(bo); - tmpImage->r(i, j) = ro; - tmpImage->g(i, j) = go; - tmpImage->b(i, j) = bo; + ro = CLIP (ro); + go = CLIP (go); + bo = CLIP (bo); + tmpImage->r (i, j) = ro; + tmpImage->g (i, j) = go; + tmpImage->b (i, j) = bo; } } } @@ -4586,7 +4621,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float reducac = 0.4f; int preser = 0; - if(params->colorToning.lumamode) { + if (params->colorToning.lumamode) { preser = 1; } @@ -4601,31 +4636,31 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer iphigh = (float)ctColorCurve.high; //2 colours - ctColorCurve.getVal(iphigh, xh, yh, zh); - ctColorCurve.getVal(iplow, xl, yl, zl); + ctColorCurve.getVal (iphigh, xh, yh, zh); + ctColorCurve.getVal (iplow, xl, yl, zl); - Color::xyz2rgb(xh, yh, zh, rh, gh, bh, wip); - Color::xyz2rgb(xl, yl, zl, rl, gl, bl, wip); + Color::xyz2rgb (xh, yh, zh, rh, gh, bh, wip); + Color::xyz2rgb (xl, yl, zl, rl, gl, bl, wip); //retrieve rgb value with s and l =1 - retreavergb(rl, gl, bl); - retreavergb(rh, gh, bh); + retreavergb (rl, gl, bl); + retreavergb (rh, gh, bh); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 5) #endif for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float r = tmpImage->r(i, j); - float g = tmpImage->g(i, j); - float b = tmpImage->b(i, j); + float r = tmpImage->r (i, j); + float g = tmpImage->g (i, j); + float b = tmpImage->b (i, j); float ro, go, bo; int mode = 1; toning2col (r, g, b, ro, go, bo, iplow, iphigh, rl, gl, bl, rh, gh, bh, SatLow, SatHigh, balanS, balanH, reducac, mode, preser, strProtect); - tmpImage->r(i, j) = ro; - tmpImage->g(i, j) = go; - tmpImage->b(i, j) = bo; + tmpImage->r (i, j) = ro; + tmpImage->g (i, j) = go; + tmpImage->b (i, j) = bo; } } } @@ -4646,13 +4681,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer metchrom = 3; } - if(metchrom == 3) { + if (metchrom == 3) { twocol = false; } float iplow = 0.f, iphigh = 0.f; - if(!twocol) { + if (!twocol) { iplow = (float)ctColorCurve.low; iphigh = (float)ctColorCurve.high; @@ -4660,7 +4695,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int twoc = 0; //integer instead of bool to let more possible choice...other than 2 and 500. - if(!twocol) { + if (!twocol) { twoc = 0; // 2 colours } else { twoc = 1; // 500 colours @@ -4668,32 +4703,32 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (params->colorToning.method == "Lab") { algm = 1; - } else if(params->colorToning.method == "Lch") { + } else if (params->colorToning.method == "Lch") { algm = 2; //in case of } - if(algm <= 2) { + if (algm <= 2) { #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 5) #endif for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float r = tmpImage->r(i, j); - float g = tmpImage->g(i, j); - float b = tmpImage->b(i, j); + float r = tmpImage->r (i, j); + float g = tmpImage->g (i, j); + float b = tmpImage->b (i, j); float ro, bo, go; labtoning (r, g, b, ro, go, bo, algm, metchrom, twoc, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, clToningcurve, cl2Toningcurve, iplow, iphigh, wp, wip); - tmpImage->r(i, j) = CLIP(ro); - tmpImage->g(i, j) = CLIP(go); - tmpImage->b(i, j) = CLIP(bo); + tmpImage->r (i, j) = CLIP (ro); + tmpImage->g (i, j) = CLIP (go); + tmpImage->b (i, j) = CLIP (bo); } } } } - else if (params->colorToning.method.substr(0, 3) == "RGB" && opautili) { + else if (params->colorToning.method.substr (0, 3) == "RGB" && opautili) { // color toning #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 5) @@ -4701,31 +4736,31 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float r = tmpImage->r(i, j); - float g = tmpImage->g(i, j); - float b = tmpImage->b(i, j); + float r = tmpImage->r (i, j); + float g = tmpImage->g (i, j); + float b = tmpImage->b (i, j); // Luminance = (0.299f*r + 0.587f*g + 0.114f*b) float h, s, l; - Color::rgb2hsl(r, g, b, h, s, l); + Color::rgb2hsl (r, g, b, h, s, l); - float l_ = Color::gamma_srgb(l * 65535.f) / 65535.f; + float l_ = Color::gamma_srgb (l * 65535.f) / 65535.f; // get the opacity and tweak it to preserve saturated colors float opacity = ctOpacityCurve.lutOpacityCurve[l_ * 500.f] / 4.f; float r2, g2, b2; - ctColorCurve.getVal(l_, r2, g2, b2); // get the color from the color curve + ctColorCurve.getVal (l_, r2, g2, b2); // get the color from the color curve float h2, s2, l2; - Color::rgb2hsl(r2, g2, b2, h2, s2, l2); // transform this new color to hsl + Color::rgb2hsl (r2, g2, b2, h2, s2, l2); // transform this new color to hsl - Color::hsl2rgb(h2, s2, l, r2, g2, b2); + Color::hsl2rgb (h2, s2, l, r2, g2, b2); - tmpImage->r(i, j) = r + (r2 - r) * opacity; - tmpImage->g(i, j) = g + (g2 - g) * opacity; - tmpImage->b(i, j) = b + (b2 - b) * opacity; + tmpImage->r (i, j) = r + (r2 - r) * opacity; + tmpImage->g (i, j) = g + (g2 - g) * opacity; + tmpImage->b (i, j) = b + (b2 - b) * opacity; } } } @@ -4760,9 +4795,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float r = tmpImage->r(i, j); - float g = tmpImage->g(i, j); - float b = tmpImage->b(i, j); + float r = tmpImage->r (i, j); + float g = tmpImage->g (i, j); + float b = tmpImage->b (i, j); float x = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b; float y = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; @@ -4770,9 +4805,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float fx, fy, fz; - fx = (x < MAXVALF ? Color::cachef[x] : 327.68f * std::cbrt(x / MAXVALF)); - fy = (y < MAXVALF ? Color::cachef[y] : 327.68f * std::cbrt(y / MAXVALF)); - fz = (z < MAXVALF ? Color::cachef[z] : 327.68f * std::cbrt(z / MAXVALF)); + fx = (x < MAXVALF ? Color::cachef[x] : 327.68f * std::cbrt (x / MAXVALF)); + fy = (y < MAXVALF ? Color::cachef[y] : 327.68f * std::cbrt (y / MAXVALF)); + fz = (z < MAXVALF ? Color::cachef[z] : 327.68f * std::cbrt (z / MAXVALF)); lab->L[i][j] = 116.0f * fy - 5242.88f; //5242.88=16.0*327.68; lab->a[i][j] = 500.0f * (fx - fy); @@ -4808,31 +4843,31 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer **/ void ImProcFunctions::retreavergb (float &r, float &g, float &b) { - float mini = min(r, g, b); - float maxi = max(r, g, b); + float mini = min (r, g, b); + float maxi = max (r, g, b); float kkm = 65535.f / maxi; - if(b == mini && r == maxi) { + if (b == mini && r == maxi) { r = 65535.f; g = kkm * (g - b); b = 0.f; - } else if(b == mini && g == maxi) { + } else if (b == mini && g == maxi) { g = 65535.f; r = kkm * (r - b); b = 0.f; - } else if(g == mini && r == maxi) { + } else if (g == mini && r == maxi) { r = 65535.f; b = kkm * (b - g); g = 0.f; - } else if(g == mini && b == maxi) { + } else if (g == mini && b == maxi) { b = 65535.f; r = kkm * (r - g); g = 0.f; - } else if(r == mini && b == maxi) { + } else if (r == mini && b == maxi) { b = 65535.f; g = kkm * (g - r); r = 0.f; - } else if(r == mini && g == maxi) { + } else if (r == mini && g == maxi) { g = 65535.f; b = kkm * (b - r); r = 0.f; @@ -4857,7 +4892,7 @@ void ImProcFunctions::secondeg_end (float reducac, float vinf, float &aa, float float a3 = 1.f - v0 * v0; float a4 = me * me - v0 * v0; aa = (1.f + (zrd - 1.f) * (1 - v0) / a2) / (a4 * (1.f - v0) / a2 - a3); - bb = -(1.f + a3 * aa) / (1.f - v0); + bb = - (1.f + a3 * aa) / (1.f - v0); cc = - (aa + bb); } @@ -4906,7 +4941,7 @@ void ImProcFunctions::toningsmh (float r, float g, float b, float &ro, float &go float GreenL = 1.f + (GreenLow - 1.f) * 0.4f; float BlueL = 1.f + (BlueLow - 1.f) * bmu; float h, s, v; - Color::rgb2hsv(r, g, b, h, s, v); + Color::rgb2hsv (r, g, b, h, s, v); float ksat = 1.f; float ksatlow = 1.f; // float s_0=0.55f; @@ -4923,10 +4958,10 @@ void ImProcFunctions::toningsmh (float r, float g, float b, float &ro, float &go float rlh = 2.2f; //1.1 float rlob = bmu; //for BW old mode - if(mode == 0) { //color - rlo *= pow_F(strProtect, 0.4f); //0.5 ==> 0.75 - rlh *= pow_F(strProtect, 0.4f); - rlm *= pow_F(strProtect, 0.4f); + if (mode == 0) { //color + rlo *= pow_F (strProtect, 0.4f); //0.5 ==> 0.75 + rlh *= pow_F (strProtect, 0.4f); + rlm *= pow_F (strProtect, 0.4f); } else { //bw coefficient to preserve same results as before for satlimtopacity = 0.5 (default) rlo = strProtect * 0.8f; //0.4 rlob = strProtect; //0.5 @@ -4934,17 +4969,17 @@ void ImProcFunctions::toningsmh (float r, float g, float b, float &ro, float &go rlh = strProtect * 2.4f; //1.2 } - if(mode == 0) { + if (mode == 0) { rlob = rlo; } //fixed value of reducac=0.3 //secondeg_end (reducac, v0, aa, bb, cc); - if(mode == 1) { + if (mode == 1) { reducac = 0.5f; //black and white mode - if(v > 0.15f) { + if (v > 0.15f) { kl = (-1.f / 0.85f) * v + (1.f) / 0.85f; //Low light ==> decrease action after v=0.15 } } else { //color @@ -4955,63 +4990,63 @@ void ImProcFunctions::toningsmh (float r, float g, float b, float &ro, float &go float aab, bbb; secondeg_begin (0.7f, v0, aab, bbb); - if(v > v0) { + if (v > v0) { kl = aa * v * v + bb * v + cc; //verified ==> exact } else if (mode == 0) { kl = aab * v * v + bbb * v; //ksatlow=ksat; } } - if(RedLow != 1.f) { + if (RedLow != 1.f) { RedL = 1.f + (RedLow - 1.f) * kl * ksat * rlo; //0.4 - if(RedLow >= 1.f) { + if (RedLow >= 1.f) { g -= 20000.f * (RedL - 1.f) * ksatlow; b -= 20000.f * (RedL - 1.f) * ksatlow; } else { r += 20000.f * (RedL - 1.f) * ksatlow; } - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); + r = CLIP (r); + g = CLIP (g); + b = CLIP (b); } - if(GreenLow != 1.f) { + if (GreenLow != 1.f) { GreenL = 1.f + (GreenLow - 1.f) * kl * ksat * rlo; //0.4 - if(GreenLow >= 1.f) { + if (GreenLow >= 1.f) { r -= 20000.f * (GreenL - 1.f) * ksatlow; b -= 20000.f * (GreenL - 1.f) * ksatlow; } else { g += 20000.f * (GreenL - 1.f) * ksatlow; } - r = CLIP(r); - b = CLIP(b); - g = CLIP(g); + r = CLIP (r); + b = CLIP (b); + g = CLIP (g); } - if(BlueLow != 1.f) { + if (BlueLow != 1.f) { BlueL = 1.f + (BlueLow - 1.f) * kl * ksat * rlob; - if(BlueLow >= 1.f) { + if (BlueLow >= 1.f) { r -= 20000.f * (BlueL - 1.f) * ksatlow; g -= 20000.f * (BlueL - 1.f) * ksatlow; } else { b += 20000.f * (BlueL - 1.f) * ksatlow; } - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); + r = CLIP (r); + g = CLIP (g); + b = CLIP (b); } // mid tones float km; float v0m = 0.5f; //max action - if(v < v0m) { + if (v < v0m) { float aam, bbm; float vend = v0m; secondeg_begin (reducac, vend, aam, bbm); @@ -5025,67 +5060,67 @@ void ImProcFunctions::toningsmh (float r, float g, float b, float &ro, float &go float RedM = 1.f + (RedMed - 1.f) * rlm; - if(RedMed != 1.f) { + if (RedMed != 1.f) { RedM = 1.f + (RedMed - 1.f) * km * rlm; - if(RedMed >= 1.f) { + if (RedMed >= 1.f) { r += 20000.f * (RedM - 1.f); g -= 10000.f * (RedM - 1.f); b -= 10000.f * (RedM - 1.f); - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); + r = CLIP (r); + g = CLIP (g); + b = CLIP (b); } else { r += 10000.f * (RedM - 1.f); g -= 20000.f * (RedM - 1.f); b -= 20000.f * (RedM - 1.f); - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); + r = CLIP (r); + g = CLIP (g); + b = CLIP (b); } } float GreenM = 1.f + (GreenMed - 1.f) * rlm; - if(GreenMed != 1.f) { + if (GreenMed != 1.f) { GreenM = 1.f + (GreenMed - 1.f) * km * rlm; - if(GreenMed >= 1.f) { + if (GreenMed >= 1.f) { r -= 10000.f * (GreenM - 1.f); g += 20000.f * (GreenM - 1.f); b -= 10000.f * (GreenM - 1.f); - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); + r = CLIP (r); + g = CLIP (g); + b = CLIP (b); } else { r -= 20000.f * (GreenM - 1.f); g += 10000.f * (GreenM - 1.f); b -= 20000.f * (GreenM - 1.f); - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); + r = CLIP (r); + g = CLIP (g); + b = CLIP (b); } } float BlueM = 1.f + (BlueMed - 1.f) * rlm; - if(BlueMed != 1.f) { + if (BlueMed != 1.f) { BlueM = 1.f + (BlueMed - 1.f) * km * rlm; - if(BlueMed >= 1.f) { + if (BlueMed >= 1.f) { r -= 10000.f * (BlueM - 1.f); g -= 10000.f * (BlueM - 1.f); b += 20000.f * (BlueM - 1.f); - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); + r = CLIP (r); + g = CLIP (g); + b = CLIP (b); } else { r -= 20000.f * (BlueM - 1.f); g -= 20000.f * (BlueM - 1.f); b += 10000.f * (BlueM - 1.f); - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); + r = CLIP (r); + g = CLIP (g); + b = CLIP (b); } } @@ -5098,7 +5133,7 @@ void ImProcFunctions::toningsmh (float r, float g, float b, float &ro, float &go // float hmu=1.5f; // if(mode==1) hmu=1.2f;//for BW old mode - if(v > v00) { + if (v > v00) { kh = (-1.f / (1.f - v00)) * v + (1.f) / (1.f - v00); //High tones } else { kh = aa0 * v * v + bb0 * v; //verification = good @@ -5108,49 +5143,49 @@ void ImProcFunctions::toningsmh (float r, float g, float b, float &ro, float &go float GreenH = 1.f + (GreenHigh - 1.f) * rlh; float BlueH = 1.f + (BlueHigh - 1.f) * rlh; //1.2 - if(RedHigh != 1.f) { + if (RedHigh != 1.f) { RedH = 1.f + (RedHigh - 1.f) * kh * rlh; //1.2 - if(RedHigh >= 1.f) { + if (RedHigh >= 1.f) { r += 20000.f * (RedH - 1.f); - r = CLIP(r); + r = CLIP (r); } else { g -= 20000.f * (RedH - 1.f); b -= 20000.f * (RedH - 1.f); } - g = CLIP(g); - b = CLIP(b); + g = CLIP (g); + b = CLIP (b); } - if(GreenHigh != 1.f) { + if (GreenHigh != 1.f) { GreenH = 1.f + (GreenHigh - 1.f) * kh * rlh; //1.2 - if(GreenHigh >= 1.f) { + if (GreenHigh >= 1.f) { g += 20000.f * (GreenH - 1.f); - g = CLIP(g); + g = CLIP (g); } else { r -= 20000.f * (GreenH - 1.f); b -= 20000.f * (GreenH - 1.f); } - r = CLIP(r); - b = CLIP(b); + r = CLIP (r); + b = CLIP (b); } - if(BlueHigh != 1.f) { + if (BlueHigh != 1.f) { BlueH = 1.f + (BlueHigh - 1.f) * kh * rlh; //1.2 - if(BlueHigh >= 1.f) { + if (BlueHigh >= 1.f) { b += 20000.f * (BlueH - 1.f); - b = CLIP(b); + b = CLIP (b); } else { r -= 20000.f * (BlueH - 1.f); g -= 20000.f * (BlueH - 1.f); } - r = CLIP(r); - g = CLIP(g); + r = CLIP (r); + g = CLIP (g); } ro = r; @@ -5174,9 +5209,9 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g { float lumbefore = 0.299f * r + 0.587f * g + 0.114f * b; float h, s, l; - Color::rgb2hsl(r, g, b, h, s, l); + Color::rgb2hsl (r, g, b, h, s, l); float v; - Color::rgb2hsv(r, g, b, h, s, v); + Color::rgb2hsv (r, g, b, h, s, v); float ksat = 1.f; float ksatlow = 1.f; /* @@ -5188,8 +5223,8 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g float kl = 1.f; float rlo = 1.f; float rlh = 2.2f; - rlo *= pow_F(strProtect, 0.4f); //0.5 ==> 0.75 transfered value for more action - rlh *= pow_F(strProtect, 0.4f); + rlo *= pow_F (strProtect, 0.4f); //0.5 ==> 0.75 transfered value for more action + rlh *= pow_F (strProtect, 0.4f); //low tones //second degree float aa, bb, cc; @@ -5199,54 +5234,54 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g secondeg_begin (0.7f, iplow, aab, bbb); - if(v > iplow) { + if (v > iplow) { kl = aa * v * v + bb * v + cc; } else if (mode == 0) { kl = aab * v * v + bbb * v; } - if(SatLow > 0.f) { + if (SatLow > 0.f) { //rl gl bl float krl = rl / (rl + gl + bl); float kgl = gl / (rl + gl + bl); float kbl = bl / (rl + gl + bl); float RedL, GreenL, BlueL; - if(g < 20000.f || b < 20000.f || r < 20000.f) { - float kmgb = min(r, g, b); //I have tested ...0.85 compromise... - kl *= pow((kmgb / 20000.f), 0.85f); + if (g < 20000.f || b < 20000.f || r < 20000.f) { + float kmgb = min (r, g, b); //I have tested ...0.85 compromise... + kl *= pow ((kmgb / 20000.f), 0.85f); } RedL = 1.f + (SatLow * krl) * kl * ksat * rlo * balanS; //0.4 - if(krl > 0.f) { + if (krl > 0.f) { g -= 20000.f * (RedL - 1.f) * ksatlow; b -= 20000.f * (RedL - 1.f) * ksatlow; } - g = CLIP(g); - b = CLIP(b); + g = CLIP (g); + b = CLIP (b); GreenL = 1.f + (SatLow * kgl) * kl * ksat * rlo * balanS; //0.4 - if(kgl > 0.f) { + if (kgl > 0.f) { r -= 20000.f * (GreenL - 1.f) * ksatlow; b -= 20000.f * (GreenL - 1.f) * ksatlow; } - r = CLIP(r); - b = CLIP(b); + r = CLIP (r); + b = CLIP (b); BlueL = 1.f + (SatLow * kbl) * kl * ksat * rlo * balanS; //0.4 - if(kbl > 0.f) { + if (kbl > 0.f) { r -= 20000.f * (BlueL - 1.f) * ksatlow; g -= 20000.f * (BlueL - 1.f) * ksatlow; } - r = CLIP(r); - g = CLIP(g); + r = CLIP (r); + g = CLIP (g); } //high tones @@ -5255,15 +5290,15 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g //fixed value of reducac ==0.4; secondeg_begin (reducac, iphigh, aa0, bb0); - if(v > iphigh) { + if (v > iphigh) { kh = (-1.f / (1.f - iphigh)) * v + (1.f) / (1.f - iphigh); //Low light ==> decrease action after iplow } else { kh = aa0 * v * v + bb0 * v; } - if(g > 45535.f || b > 45535.f || r > 45535.f) { - float kmgb = max(r, g, b); + if (g > 45535.f || b > 45535.f || r > 45535.f) { + float kmgb = max (r, g, b); float cora = 1.f / (45535.f - 65535.f); float corb = 1.f - cora * 45535.f; float cor = kmgb * cora + corb; @@ -5276,45 +5311,45 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g } - if(SatHigh > 0.f) { + if (SatHigh > 0.f) { float RedH, GreenH, BlueH; float krh = rh / (rh + gh + bh); float kgh = gh / (rh + gh + bh); float kbh = bh / (rh + gh + bh); RedH = 1.f + (SatHigh * krh) * kh * rlh * balanH; //1.2 - if(krh > 0.f) { + if (krh > 0.f) { r += 20000.f * (RedH - 1.f); - r = CLIP(r); + r = CLIP (r); } - g = CLIP(g); - b = CLIP(b); + g = CLIP (g); + b = CLIP (b); GreenH = 1.f + (SatHigh * kgh) * kh * rlh * balanH; //1.2 - if(kgh > 0.f) { + if (kgh > 0.f) { g += 20000.f * (GreenH - 1.f); - g = CLIP(g); + g = CLIP (g); } - r = CLIP(r); - b = CLIP(b); + r = CLIP (r); + b = CLIP (b); BlueH = 1.f + (SatHigh * kbh) * kh * rlh * balanH; //1.2 - if(kbh > 0.f) { + if (kbh > 0.f) { b += 20000.f * (BlueH - 1.f); - b = CLIP(b); + b = CLIP (b); } - r = CLIP(r); - g = CLIP(g); + r = CLIP (r); + g = CLIP (g); } float lumafter = 0.299f * r + 0.587f * g + 0.114f * b; float preserv = 1.f; - if(preser == 1) { + if (preser == 1) { preserv = lumbefore / lumafter; } @@ -5325,9 +5360,9 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g ro *= preserv; go *= preserv; bo *= preserv; - ro = CLIP(ro); - go = CLIP(go); - bo = CLIP(bo); + ro = CLIP (ro); + go = CLIP (go); + bo = CLIP (bo); } /** @@ -5346,21 +5381,21 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go { float realL; float h, s, l; - Color::rgb2hsl(r, g, b, h, s, l); + Color::rgb2hsl (r, g, b, h, s, l); float x2, y2, z2; float xl, yl, zl; - if(twoc != 1) { + if (twoc != 1) { l = (Color::gammatab_13_2[ l * 65535.f]) / 65535.f; //to compensate L from Lab iphigh = (Color::gammatab_13_2[iphigh * 65535.f]) / 65535.f; iplow = (Color::gammatab_13_2[ iplow * 65535.f]) / 65535.f; } - if(twoc == 1) { - ctColorCurve.getVal(l, x2, y2, z2); + if (twoc == 1) { + ctColorCurve.getVal (l, x2, y2, z2); } else { - ctColorCurve.getVal(iphigh, x2, y2, z2); - ctColorCurve.getVal(iplow, xl, yl, zl); + ctColorCurve.getVal (iphigh, x2, y2, z2); + ctColorCurve.getVal (iplow, xl, yl, zl); } realL = l; @@ -5372,8 +5407,8 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go // get the opacity and tweak it to preserve saturated colors //float l_ = Color::gamma_srgb(l*65535.f)/65535.f; float opacity; - opacity = (1.f - min<float>(s / satLimit, 1.f) * (1.f - satLimitOpacity)) * ctOpacityCurve.lutOpacityCurve[l * 500.f]; - float opacity2 = (1.f - min<float>(s / satLimit, 1.f) * (1.f - satLimitOpacity)); + opacity = (1.f - min<float> (s / satLimit, 1.f) * (1.f - satLimitOpacity)) * ctOpacityCurve.lutOpacityCurve[l * 500.f]; + float opacity2 = (1.f - min<float> (s / satLimit, 1.f) * (1.f - satLimitOpacity)); //float ro, go, bo; bool chr = true; @@ -5382,23 +5417,23 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go float chromat, luma; if (clToningcurve[lm * 65535.f] / (lm * 65535.f) < 1.f) { - chromat = (clToningcurve[(lm) * 65535.f] / (lm * 65535.f)) - 1.f; //special effect + chromat = (clToningcurve[ (lm) * 65535.f] / (lm * 65535.f)) - 1.f; //special effect } else { - chromat = 1.f - SQR(SQR((lm * 65535.f) / clToningcurve[(lm) * 65535.f])); //apply C=f(L) acts on 'a' and 'b' + chromat = 1.f - SQR (SQR ((lm * 65535.f) / clToningcurve[ (lm) * 65535.f])); //apply C=f(L) acts on 'a' and 'b' } if (cl2Toningcurve[lm * 65535.f] / (lm * 65535.f) < 1.f) { - luma = (cl2Toningcurve[(lm) * 65535.f] / (lm * 65535.f)) - 1.f; //special effect + luma = (cl2Toningcurve[ (lm) * 65535.f] / (lm * 65535.f)) - 1.f; //special effect } else { - luma = 1.f - SQR(SQR((lm * 65535.f) / (cl2Toningcurve[(lm) * 65535.f]))); //apply C2=f(L) acts only on 'b' + luma = 1.f - SQR (SQR ((lm * 65535.f) / (cl2Toningcurve[ (lm) * 65535.f]))); //apply C2=f(L) acts only on 'b' } int todo = 1; if (algm == 1) { - Color::interpolateRGBColor(realL, iplow, iphigh, algm, opacity, twoc, metchrom, chr, lum, chromat, luma, r, g, b, xl, yl, zl, x2, y2, z2, todo, wp, wip, ro, go, bo); + Color::interpolateRGBColor (realL, iplow, iphigh, algm, opacity, twoc, metchrom, chr, lum, chromat, luma, r, g, b, xl, yl, zl, x2, y2, z2, todo, wp, wip, ro, go, bo); } else { - Color::interpolateRGBColor(realL, iplow, iphigh, algm, opacity2, twoc, metchrom, chr, lum, chromat, luma, r, g, b, xl, yl, zl, x2, y2, z2, todo, wp, wip, ro, go, bo); + Color::interpolateRGBColor (realL, iplow, iphigh, algm, opacity2, twoc, metchrom, chr, lum, chromat, luma, r, g, b, xl, yl, zl, x2, y2, z2, todo, wp, wip, ro, go, bo); } } @@ -5456,7 +5491,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu bool chutili = false; if (params->labCurve.chromaticity > -100) { - chCurve = new FlatCurve(params->labCurve.chcurve); + chCurve = new FlatCurve (params->labCurve.chcurve); if (!chCurve || chCurve->isIdentity()) { if (chCurve) { @@ -5473,7 +5508,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu bool lhutili = false; if (params->labCurve.chromaticity > -100) { - lhCurve = new FlatCurve(params->labCurve.lhcurve); + lhCurve = new FlatCurve (params->labCurve.lhcurve); if (!lhCurve || lhCurve->isIdentity()) { if (lhCurve) { @@ -5490,7 +5525,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu bool hhutili = false; if (params->labCurve.chromaticity > -100) { - hhCurve = new FlatCurve(params->labCurve.hhcurve); + hhCurve = new FlatCurve (params->labCurve.hhcurve); if (!hhCurve || hhCurve->isIdentity()) { if (hhCurve) { @@ -5508,10 +5543,10 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu LUTu hist16Llad; //preparate for histograms CIECAM - if(pW != 1) { //only with improccoordinator - hist16Clad(65536); + if (pW != 1) { //only with improccoordinator + hist16Clad (65536); hist16Clad.clear(); - hist16Llad(65536); + hist16Llad (65536); hist16Llad.clear(); } @@ -5565,38 +5600,38 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu float protect_red, protect_redh; protect_red = protectRed;//default=60 chroma: one can put more or less if necessary...in 'option' 40...160 - if(protect_red < 20.0f) { + if (protect_red < 20.0f) { protect_red = 20.0; // avoid too low value } - if(protect_red > 180.0f) { + if (protect_red > 180.0f) { protect_red = 180.0; // avoid too high value } - protect_redh = float(protectRedH); //default=0.4 rad : one can put more or less if necessary...in 'option' 0.2 ..1.0 + protect_redh = float (protectRedH); //default=0.4 rad : one can put more or less if necessary...in 'option' 0.2 ..1.0 - if(protect_redh < 0.1f) { + if (protect_redh < 0.1f) { protect_redh = 0.1f; //avoid divide by 0 and negatives values } - if(protect_redh > 1.0f) { + if (protect_redh > 1.0f) { protect_redh = 1.0f; //avoid too big values } float protect_redhcur = protectRedH;//default=0.4 rad : one can put more or less if necessary...in 'option' 0.2 ..1 - if(protect_redhcur < 0.1f) { + if (protect_redhcur < 0.1f) { protect_redhcur = 0.1f; //avoid divide by 0 and negatives values:minimal protection for transition } - if(protect_redhcur > 3.5f) { + if (protect_redhcur > 3.5f) { protect_redhcur = 3.5f; //avoid too big values } //increase saturation after denoise : ...approximation float factnoise = 1.f; - if(params->dirpyrDenoise.enabled) { + if (params->dirpyrDenoise.enabled) { factnoise = (1.f + params->dirpyrDenoise.chroma / 500.f); //levels=5 // if(yyyy) factnoise=(1.f+params->dirpyrDenoise.chroma/100.f);//levels=7 } @@ -5637,28 +5672,28 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (avoidColorShift) // only if user activate Lab adjustments - if(autili || butili || ccutili || cclutili || chutili || lhutili || hhutili || clcutili || utili || chromaticity) { - Color::LabGamutMunsell(lold->L[i], lold->a[i], lold->b[i], W, /*corMunsell*/true, /*lumaMuns*/false, params->toneCurve.hrenabled, /*gamut*/true, wip, multiThread); + if (autili || butili || ccutili || cclutili || chutili || lhutili || hhutili || clcutili || utili || chromaticity) { + Color::LabGamutMunsell (lold->L[i], lold->a[i], lold->b[i], W, /*corMunsell*/true, /*lumaMuns*/false, params->toneCurve.hrenabled, /*gamut*/true, wip, multiThread); } #ifdef __SSE2__ // precalculate some values using SSE - if(bwToning || (!autili && !butili)) { - __m128 c327d68v = _mm_set1_ps(327.68f); + if (bwToning || (!autili && !butili)) { + __m128 c327d68v = _mm_set1_ps (327.68f); __m128 av, bv; int k; for (k = 0; k < W - 3; k += 4) { - av = LVFU(lold->a[i][k]); - bv = LVFU(lold->b[i][k]); - STVF(HHBuffer[k], xatan2f(bv, av)); - STVF(CCBuffer[k], _mm_sqrt_ps(SQRV(av) + SQRV(bv)) / c327d68v); + av = LVFU (lold->a[i][k]); + bv = LVFU (lold->b[i][k]); + STVF (HHBuffer[k], xatan2f (bv, av)); + STVF (CCBuffer[k], _mm_sqrt_ps (SQRV (av) + SQRV (bv)) / c327d68v); } - for(; k < W; k++) { - HHBuffer[k] = xatan2f(lold->b[i][k], lold->a[i][k]); - CCBuffer[k] = sqrt(SQR(lold->a[i][k]) + SQR(lold->b[i][k])) / 327.68f; + for (; k < W; k++) { + HHBuffer[k] = xatan2f (lold->b[i][k], lold->a[i][k]); + CCBuffer[k] = sqrt (SQR (lold->a[i][k]) + SQR (lold->b[i][k])) / 327.68f; } } @@ -5674,18 +5709,18 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu float memChprov; float2 sincosval; - if(bwToning) { // this values will be also set when bwToning is false some lines down + if (bwToning) { // this values will be also set when bwToning is false some lines down #ifdef __SSE2__ // use precalculated values from above HH = HHBuffer[j]; CC = CCBuffer[j]; #else - HH = xatan2f(lold->b[i][j], lold->a[i][j]); - CC = sqrt(SQR(lold->a[i][j]) + SQR(lold->b[i][j])) / 327.68f; + HH = xatan2f (lold->b[i][j], lold->a[i][j]); + CC = sqrt (SQR (lold->a[i][j]) + SQR (lold->b[i][j])) / 327.68f; #endif // According to mathematical laws we can get the sin and cos of HH by simple operations - if(CC == 0.0f) { + if (CC == 0.0f) { sincosval.y = 1.0f; sincosval.x = 0.0f; } else { @@ -5699,20 +5734,20 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } if (editPipette && editID == EUID_Lab_LCurve) { - editWhatever->v(i, j) = LIM01<float>(Lin / 32768.0f); // Lab L pipette + editWhatever->v (i, j) = LIM01<float> (Lin / 32768.0f); // Lab L pipette } lnew->L[i][j] = curve[Lin]; float Lprov1 = (lnew->L[i][j]) / 327.68f; - if(editPipette) { + if (editPipette) { if (editID == EUID_Lab_aCurve) { // Lab a pipette float chromapipa = lold->a[i][j] + (32768.f * 1.28f); - editWhatever->v(i, j) = LIM01<float>((chromapipa) / (65536.f * 1.28f)); + editWhatever->v (i, j) = LIM01<float> ((chromapipa) / (65536.f * 1.28f)); } else if (editID == EUID_Lab_bCurve) { //Lab b pipette float chromapipb = lold->b[i][j] + (32768.f * 1.28f); - editWhatever->v(i, j) = LIM01<float>((chromapipb) / (65536.f * 1.28f)); + editWhatever->v (i, j) = LIM01<float> ((chromapipb) / (65536.f * 1.28f)); } } @@ -5720,35 +5755,35 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu atmp = lold->a[i][j]; - if(autili) { + if (autili) { atmp = acurve[atmp + 32768.0f] - 32768.0f; // curves Lab a } btmp = lold->b[i][j]; - if(butili) { + if (butili) { btmp = bcurve[btmp + 32768.0f] - 32768.0f; // curves Lab b } - if(!bwToning) { //take into account modification of 'a' and 'b' + if (!bwToning) { //take into account modification of 'a' and 'b' #ifdef __SSE2__ - if(!autili && !butili) { + if (!autili && !butili) { // use precalculated values from above HH = HHBuffer[j]; CC = CCBuffer[j]; } else { - CC = sqrt(SQR(atmp) + SQR(btmp)) / 327.68f; - HH = xatan2f(btmp, atmp); + CC = sqrt (SQR (atmp) + SQR (btmp)) / 327.68f; + HH = xatan2f (btmp, atmp); } #else - CC = sqrt(SQR(atmp) + SQR(btmp)) / 327.68f; - HH = xatan2f(btmp, atmp); + CC = sqrt (SQR (atmp) + SQR (btmp)) / 327.68f; + HH = xatan2f (btmp, atmp); #endif // According to mathematical laws we can get the sin and cos of HH by simple operations //float2 sincosval; - if(CC == 0.f) { + if (CC == 0.f) { sincosval.y = 1.f; sincosval.x = 0.f; } else { @@ -5761,10 +5796,10 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu memChprov = Chprov; } // now new values of lold with 'a' and 'b' - if(editPipette) + if (editPipette) if (editID == EUID_Lab_LHCurve || editID == EUID_Lab_CHCurve || editID == EUID_Lab_HHCurve) {//H pipette - float valpar = Color::huelab_to_huehsv2(HH); - editWhatever->v(i, j) = valpar; + float valpar = Color::huelab_to_huehsv2 (HH); + editWhatever->v (i, j) = valpar; } if (lhutili) { // L=f(H) @@ -5772,7 +5807,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu float l_r;//Luminance Lab in 0..1 l_r = Lprov1 / 100.f; { - float valparam = float((lhCurve->getVal(Color::huelab_to_huehsv2(HH)) - 0.5f)); //get l_r=f(H) + float valparam = float ((lhCurve->getVal (Color::huelab_to_huehsv2 (HH)) - 0.5f)); //get l_r=f(H) float valparamneg; valparamneg = valparam; float kcc = (CC / amountchroma); //take Chroma into account...40 "middle low" of chromaticity (arbitrary and simple), one can imagine other algorithme @@ -5780,8 +5815,8 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu valparam *= 2.f * kcc; valparamneg *= kcc; //slightly different for negative - if(valparam > 0.f) { - l_r = (1.f - valparam) * l_r + valparam * (1.f - SQR(((SQR(1.f - min(l_r, 1.0f)))))); + if (valparam > 0.f) { + l_r = (1.f - valparam) * l_r + valparam * (1.f - SQR (((SQR (1.f - min (l_r, 1.0f)))))); } else //for negative { @@ -5792,7 +5827,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu Lprov1 = l_r * 100.f; - float Chprov2 = sqrt(SQR(atmp) + SQR(btmp)) / 327.68f; + float Chprov2 = sqrt (SQR (atmp) + SQR (btmp)) / 327.68f; //Gamut control especialy fot negative values slightly different of gamutlchonly bool inRGB; @@ -5805,14 +5840,14 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu float fx = (0.002f * aprov1) + fy; float fz = fy - (0.005f * bprov1); - float x_ = 65535.0f * Color::f2xyz(fx) * Color::D50x; - float z_ = 65535.0f * Color::f2xyz(fz) * Color::D50z; + float x_ = 65535.0f * Color::f2xyz (fx) * Color::D50x; + float z_ = 65535.0f * Color::f2xyz (fz) * Color::D50z; float y_ = (Lprov1 > Color::epskap) ? 65535.0 * fy * fy * fy : 65535.0 * Lprov1 / Color::kappa; float R, G, B; - Color::xyz2rgb(x_, y_, z_, R, G, B, wip); + Color::xyz2rgb (x_, y_, z_, R, G, B, wip); if (R < 0.0f || G < 0.0f || B < 0.0f) { - if(Lprov1 < 0.1f) { + if (Lprov1 < 0.1f) { Lprov1 = 0.1f; } @@ -5834,8 +5869,8 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu // calculate C=f(H) if (chutili) { - double hr = Color::huelab_to_huehsv2(HH); - float chparam = float((chCurve->getVal(hr) - 0.5f) * 2.0f); //get C=f(H) + double hr = Color::huelab_to_huehsv2 (HH); + float chparam = float ((chCurve->getVal (hr) - 0.5f) * 2.0f); //get C=f(H) float chromaChfactor = 1.0f + chparam; atmp *= chromaChfactor;//apply C=f(H) btmp *= chromaChfactor; @@ -5843,15 +5878,15 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (hhutili) { // H=f(H) //hue Lab in -PI +PI - float valparam = float((hhCurve->getVal(Color::huelab_to_huehsv2(HH)) - 0.5f) * 1.7f) + HH; //get H=f(H) 1.7 optimisation ! + float valparam = float ((hhCurve->getVal (Color::huelab_to_huehsv2 (HH)) - 0.5f) * 1.7f) + HH; //get H=f(H) 1.7 optimisation ! HH = valparam; - sincosval = xsincosf(HH); + sincosval = xsincosf (HH); } - if(!bwToning) { + if (!bwToning) { float factorskin, factorsat, factorskinext; - if(chromapro > 1.f) { + if (chromapro > 1.f) { float scale = scaleConst;//reduction in normal zone float scaleext = 1.f;//reduction in transition zone Color::scalered ( rstprotection, chromapro, 0.0, HH, protect_redh, scale, scaleext);//1.0 @@ -5870,11 +5905,11 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (Lprov1 < 25.f) { dred = 40.f; - } else if(Lprov1 < 30.f) { + } else if (Lprov1 < 30.f) { dred = 3.f * Lprov1 - 35.f; - } else if(Lprov1 < 70.f) { + } else if (Lprov1 < 70.f) { dred = 55.f; - } else if(Lprov1 < 75.f) { + } else if (Lprov1 < 75.f) { dred = -3.f * Lprov1 + 265.f; } else { dred = 40.f; @@ -5888,7 +5923,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu btmp *= factorsat; if (editPipette && editID == EUID_Lab_CLCurve) { - editWhatever->v(i, j) = LIM01<float>(LL / 100.f); // Lab C=f(L) pipette + editWhatever->v (i, j) = LIM01<float> (LL / 100.f); // Lab C=f(L) pipette } if (clut) { // begin C=f(L) @@ -5901,31 +5936,31 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu float deltaHH;//HH value transition for C curve protect_redcur = curf * protectRed; //default=60 chroma: one can put more or less if necessary...in 'option' 40...160==> curf =because curve is more progressive - if(protect_redcur < 20.0f) { + if (protect_redcur < 20.0f) { protect_redcur = 20.0; // avoid too low value } - if(protect_redcur > 180.0f) { + if (protect_redcur > 180.0f) { protect_redcur = 180.0; // avoid too high value } - protect_redhcur = curf * float(protectRedH); //default=0.4 rad : one can put more or less if necessary...in 'option' 0.2 ..1.0 ==> curf =because curve is more progressive + protect_redhcur = curf * float (protectRedH); //default=0.4 rad : one can put more or less if necessary...in 'option' 0.2 ..1.0 ==> curf =because curve is more progressive - if(protect_redhcur < 0.1f) { + if (protect_redhcur < 0.1f) { protect_redhcur = 0.1f; //avoid divide by 0 and negatives values } - if(protect_redhcur > 1.0f) { + if (protect_redhcur > 1.0f) { protect_redhcur = 1.0f; //avoid too big values } deltaHH = protect_redhcur; //transition hue - if(chromaCfactor > 0.0) { + if (chromaCfactor > 0.0) { Color::scalered ( rstprotection, chromaCfactor, 0.0, HH, deltaHH, scale, scaleext); //1.0 } - if(chromaCfactor > 1.0) { + if (chromaCfactor > 1.0) { float interm = (chromaCfactor - 1.0f) * 100.0f; factorskin = 1.0f + (interm * scale) / 100.0f; factorskinext = 1.0f + (interm * scaleext) / 100.0f; @@ -5947,13 +5982,13 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu // I have placed C=f(C) after all C treatments to assure maximum amplitude of "C" if (editPipette && editID == EUID_Lab_CCurve) { - float chromapip = sqrt(SQR(atmp) + SQR(btmp) + 0.001f); - editWhatever->v(i, j) = LIM01<float>((chromapip) / (48000.f)); + float chromapip = sqrt (SQR (atmp) + SQR (btmp) + 0.001f); + editWhatever->v (i, j) = LIM01<float> ((chromapip) / (48000.f)); }//Lab C=f(C) pipette if (ccut) { float factorskin, factorsat, factor, factorskinext; - float chroma = sqrt(SQR(atmp) + SQR(btmp) + 0.001f); + float chroma = sqrt (SQR (atmp) + SQR (btmp) + 0.001f); float chromaCfactor = (satcurve[chroma * adjustr]) / (chroma * adjustr); //apply C=f(C) float curf = 0.7f; //empirical coeff because curve is more progressive float scale = 100.0f / 100.1f; //reduction in normal zone for curve CC @@ -5962,31 +5997,31 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu float deltaHH;//HH value transition for CC curve protect_redcur = curf * protectRed; //default=60 chroma: one can put more or less if necessary...in 'option' 40...160==> curf =because curve is more progressive - if(protect_redcur < 20.0f) { + if (protect_redcur < 20.0f) { protect_redcur = 20.0; // avoid too low value } - if(protect_redcur > 180.0f) { + if (protect_redcur > 180.0f) { protect_redcur = 180.0; // avoid too high value } - protect_redhcur = curf * float(protectRedH); //default=0.4 rad : one can put more or less if necessary...in 'option' 0.2 ..1.0 ==> curf =because curve is more progressive + protect_redhcur = curf * float (protectRedH); //default=0.4 rad : one can put more or less if necessary...in 'option' 0.2 ..1.0 ==> curf =because curve is more progressive - if(protect_redhcur < 0.1f) { + if (protect_redhcur < 0.1f) { protect_redhcur = 0.1f; //avoid divide by 0 and negatives values } - if(protect_redhcur > 1.0f) { + if (protect_redhcur > 1.0f) { protect_redhcur = 1.0f; //avoid too big values } deltaHH = protect_redhcur; //transition hue - if(chromaCfactor > 0.0) { + if (chromaCfactor > 0.0) { Color::scalered ( rstprotection, chromaCfactor, 0.0, HH, deltaHH, scale, scaleext); //1.0 } - if(chromaCfactor > 1.0) { + if (chromaCfactor > 1.0) { float interm = (chromaCfactor - 1.0f) * 100.0f; factorskin = 1.0f + (interm * scale) / 100.0f; factorskinext = 1.0f + (interm * scaleext) / 100.0f; @@ -6009,14 +6044,14 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu // end chroma C=f(C) //update histogram C - if(pW != 1) { //only with improccoordinator - int posp = (int)sqrt(atmp * atmp + btmp * btmp); + if (pW != 1) { //only with improccoordinator + int posp = (int)sqrt (atmp * atmp + btmp * btmp); hist16Clad[posp]++; } if (editPipette && editID == EUID_Lab_LCCurve) { - float chromapiplc = sqrt(SQR(atmp) + SQR(btmp) + 0.001f); - editWhatever->v(i, j) = LIM01<float>((chromapiplc) / (48000.f)); + float chromapiplc = sqrt (SQR (atmp) + SQR (btmp) + 0.001f); + editWhatever->v (i, j) = LIM01<float> ((chromapiplc) / (48000.f)); }//Lab L=f(C) pipette @@ -6034,43 +6069,43 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu float zz = 0.0f; float yy = 0.0f; - if(Chprov1 < chrmin) { - yy = SQR(Chprov1 / chrmin) * xx; + if (Chprov1 < chrmin) { + yy = SQR (Chprov1 / chrmin) * xx; } else { yy = xx; //avoid artifact for low C } - if(!LCredsk) { + if (!LCredsk) { skbeg = -3.1415; skend = 3.14159; skdeltaHH = 0.001f; } - if(HH > skbeg && HH < skend ) { + if (HH > skbeg && HH < skend ) { zz = yy; - } else if(HH > skbeg - skdeltaHH && HH <= skbeg) { //transition + } else if (HH > skbeg - skdeltaHH && HH <= skbeg) { //transition aa = yy / skdeltaHH; bb = -aa * (skbeg - skdeltaHH); zz = aa * HH + bb; - } else if(HH >= skend && HH < skend + skdeltaHH) { //transition + } else if (HH >= skend && HH < skend + skdeltaHH) { //transition aa = -yy / skdeltaHH; bb = -aa * (skend + skdeltaHH); zz = aa * HH + bb; } - float chroma = sqrt(SQR(atmp) + SQR(btmp) + 0.001f); + float chroma = sqrt (SQR (atmp) + SQR (btmp) + 0.001f); float Lc = (lhskcurve[chroma * adjustr]) / (chroma * adjustr); //apply L=f(C) Lc = (Lc - 1.0f) * zz + 1.0f; //reduct action Lprov1 *= Lc; //adjust luminance } //update histo LC - if(pW != 1) { //only with improccoordinator + if (pW != 1) { //only with improccoordinator int posl = Lprov1 * 327.68f; hist16Llad[posl]++; } - Chprov1 = sqrt(SQR(atmp) + SQR(btmp)) / 327.68f; + Chprov1 = sqrt (SQR (atmp) + SQR (btmp)) / 327.68f; // labCurve.bwtoning option allows to decouple modulation of a & b curves by saturation // with bwtoning enabled the net effect of a & b curves is visible @@ -6081,17 +6116,17 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (avoidColorShift) { //gamutmap Lch ==> preserve Hue,but a little slower than gamutbdy for high values...and little faster for low values - if(gamutLch) { + if (gamutLch) { float R, G, B; #ifdef _DEBUG bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly (HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly (HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); #endif lnew->L[i][j] = Lprov1 * 327.68f; // float2 sincosval = xsincosf(HH); @@ -6101,9 +6136,9 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu //use gamutbdy //Luv limiter float Y, u, v; - Color::Lab2Yuv(lnew->L[i][j], atmp, btmp, Y, u, v); + Color::Lab2Yuv (lnew->L[i][j], atmp, btmp, Y, u, v); //Yuv2Lab includes gamut restriction map - Color::Yuv2Lab(Y, u, v, lnew->L[i][j], lnew->a[i][j], lnew->b[i][j], wp); + Color::Yuv2Lab (Y, u, v, lnew->L[i][j], lnew->a[i][j], lnew->b[i][j], wp); } if (utili || autili || butili || ccut || clut || cclutili || chutili || lhutili || hhutili || clcutili || chromaticity) { @@ -6111,16 +6146,16 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu float correctlum = 0.f; Lprov1 = lnew->L[i][j] / 327.68f; - Chprov = sqrt(SQR(lnew->a[i][j]) + SQR(lnew->b[i][j])) / 327.68f; + Chprov = sqrt (SQR (lnew->a[i][j]) + SQR (lnew->b[i][j])) / 327.68f; #ifdef _DEBUG - Color::AllMunsellLch(/*lumaMuns*/true, Lprov1, LL, HH, Chprov, memChprov, correctionHue, correctlum, MunsDebugInfo); + Color::AllMunsellLch (/*lumaMuns*/true, Lprov1, LL, HH, Chprov, memChprov, correctionHue, correctlum, MunsDebugInfo); #else - Color::AllMunsellLch(/*lumaMuns*/true, Lprov1, LL, HH, Chprov, memChprov, correctionHue, correctlum); + Color::AllMunsellLch (/*lumaMuns*/true, Lprov1, LL, HH, Chprov, memChprov, correctionHue, correctlum); #endif - if(correctionHue != 0.f || correctlum != 0.f) { - if(fabs(correctionHue) < 0.015f) { + if (correctionHue != 0.f || correctlum != 0.f) { + if (fabs (correctionHue) < 0.015f) { HH += correctlum; // correct only if correct Munsell chroma very little. } @@ -6130,7 +6165,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu else if(fabs(correctionHue) < 0.1f) HH+=0.35f*correctlum; else if(fabs(correctionHue) < 0.015f) HH+=correctlum; // correct only if correct Munsell chroma very little. */ - sincosval = xsincosf(HH + correctionHue); + sincosval = xsincosf (HH + correctionHue); } lnew->a[i][j] = 327.68f * Chprov * sincosval.y; // apply Munsell @@ -6139,7 +6174,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } else { // if(Lprov1 > maxlp) maxlp=Lprov1; // if(Lprov1 < minlp) minlp=Lprov1; - if(!bwToning) { + if (!bwToning) { lnew->L[i][j] = Lprov1 * 327.68f; // float2 sincosval = xsincosf(HH); lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; @@ -6154,20 +6189,20 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } // end of parallelization - if(pW != 1) { //only with improccoordinator + if (pW != 1) { //only with improccoordinator //update histogram C with data chromaticity and not with CC curve - hist16Clad.compressTo(histCCurve); + hist16Clad.compressTo (histCCurve); //update histogram L with data luminance - hist16Llad.compressTo(histLCurve); + hist16Llad.compressTo (histLCurve); } #ifdef _DEBUG 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=%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); + 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=%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; @@ -6298,69 +6333,69 @@ void ImProcFunctions::defringe (LabImage* lab) if (params->defringe.enabled && lab->W >= 8 && lab->H >= 8) { - PF_correct_RT(lab, lab, params->defringe.radius, params->defringe.threshold); + PF_correct_RT (lab, lab, params->defringe.radius, params->defringe.threshold); } } void ImProcFunctions::defringecam (CieImage* ncie) { if (params->defringe.enabled && ncie->W >= 8 && ncie->H >= 8) { - PF_correct_RTcam(ncie, ncie, params->defringe.radius, params->defringe.threshold); + PF_correct_RTcam (ncie, ncie, params->defringe.radius, params->defringe.threshold); } } -void ImProcFunctions::badpixcam(CieImage* ncie, double rad, int thr, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom, int hotbad) +void ImProcFunctions::badpixcam (CieImage* ncie, double rad, int thr, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom, int hotbad) { - if(ncie->W >= 8 && ncie->H >= 8) { - Badpixelscam(ncie, ncie, rad, thr, mode, b_l, t_l, t_r, b_r, skinprot, chrom, hotbad); + if (ncie->W >= 8 && ncie->H >= 8) { + Badpixelscam (ncie, ncie, rad, thr, mode, b_l, t_l, t_r, b_r, skinprot, chrom, hotbad); } } -void ImProcFunctions::badpixlab(LabImage* lab, double rad, int thr, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom) +void ImProcFunctions::badpixlab (LabImage* lab, double rad, int thr, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom) { - if(lab->W >= 8 && lab->H >= 8) { - BadpixelsLab(lab, lab, rad, thr, mode, b_l, t_l, t_r, b_r, skinprot, chrom); + if (lab->W >= 8 && lab->H >= 8) { + BadpixelsLab (lab, lab, rad, thr, mode, b_l, t_l, t_r, b_r, skinprot, chrom); } } void ImProcFunctions::dirpyrequalizer (LabImage* lab, int scale) { if (params->dirpyrequalizer.enabled && lab->W >= 8 && lab->H >= 8) { - float b_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[0]) / 100.0f; - float t_l = static_cast<float>(params->dirpyrequalizer.hueskin.value[1]) / 100.0f; - float b_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[2]) / 100.0f; - float t_r = static_cast<float>(params->dirpyrequalizer.hueskin.value[3]) / 100.0f; + float b_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[0]) / 100.0f; + float t_l = static_cast<float> (params->dirpyrequalizer.hueskin.value[1]) / 100.0f; + float b_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[2]) / 100.0f; + float t_r = static_cast<float> (params->dirpyrequalizer.hueskin.value[3]) / 100.0f; int choice = 0; //I have not disabled this statement in case of ! always 0 // if (params->dirpyrequalizer.algo=="FI") choice=0; // else if(params->dirpyrequalizer.algo=="LA") choice=1; float artifact = (float) settings->artifact_cbdl; - if(artifact > 6.f) { + if (artifact > 6.f) { artifact = 6.f; } - if(artifact < 0.f) { + if (artifact < 0.f) { artifact = 1.f; } float chrom = 50.f; - if(params->dirpyrequalizer.gamutlab) { + if (params->dirpyrequalizer.gamutlab) { ImProcFunctions::badpixlab (lab, artifact, 5, 3, b_l, t_l, t_r, b_r, params->dirpyrequalizer.skinprotect, chrom); //for artifacts } //dirpyrLab_equalizer(lab, lab, params->dirpyrequalizer.mult); - dirpyr_equalizer(lab->L, lab->L, lab->W, lab->H, lab->a, lab->b, lab->a, lab->b, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, params->dirpyrequalizer.gamutlab, b_l, t_l, t_r, b_r, choice, scale); + dirpyr_equalizer (lab->L, lab->L, lab->W, lab->H, lab->a, lab->b, lab->a, lab->b, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, params->dirpyrequalizer.gamutlab, b_l, t_l, t_r, b_r, choice, scale); } } -void ImProcFunctions::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, int skip) +void ImProcFunctions::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, int skip) { - if(!params->epd.enabled) { + if (!params->epd.enabled) { return; } - if(params->wavelet.enabled && params->wavelet.tmrs != 0) { + if (params->wavelet.enabled && params->wavelet.tmrs != 0) { return; } @@ -6373,14 +6408,14 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, float w float *Qpr = ncie->Q_p[0]; if (settings->verbose) { - printf("minQ=%f maxQ=%f Qpro=%f\n", minQ, maxQ, Qpro); + printf ("minQ=%f maxQ=%f Qpro=%f\n", minQ, maxQ, Qpro); } - if(maxQ > Qpro) { + if (maxQ > Qpro) { Qpro = maxQ; } - EdgePreservingDecomposition epd(Wid, Hei); + EdgePreservingDecomposition epd (Wid, Hei); #pragma omp parallel for @@ -6389,24 +6424,24 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, float w ncie->Q_p[i][j] = gamm * ncie->Q_p[i][j] / (Qpro); } - float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. + float Compression = expf (-stren); //This modification turns numbers symmetric around 0 into exponents. float DetailBoost = stren; - if(stren < 0.0f) { + if (stren < 0.0f) { DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. } //Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur. - if(Iterates == 0) { - Iterates = (unsigned int)(edgest * 15.0); + if (Iterates == 0) { + Iterates = (unsigned int) (edgest * 15.0); } //Jacques Desmis : always Iterates=5 for compatibility images between preview and output - epd.CompressDynamicRange(Qpr, (float)sca / skip, (float)edgest, Compression, DetailBoost, Iterates, rew, Qpr); + epd.CompressDynamicRange (Qpr, (float)sca / skip, (float)edgest, Compression, DetailBoost, Iterates, rew, Qpr); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. - float s = (1.0f + 38.7889f) * powf(Compression, 1.5856f) / (1.0f + 38.7889f * powf(Compression, 1.5856f)); + float s = (1.0f + 38.7889f) * powf (Compression, 1.5856f) / (1.0f + 38.7889f * powf (Compression, 1.5856f)); #ifndef _DEBUG #pragma omp parallel for schedule(dynamic,10) #endif @@ -6459,18 +6494,18 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, float w //Map tones by way of edge preserving decomposition. Is this the right way to include source? //#include "EdgePreservingDecomposition.cc" -void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) +void ImProcFunctions::EPDToneMap (LabImage *lab, unsigned int Iterates, int skip) { //Hasten access to the parameters. // EPDParams *p = (EPDParams *)(¶ms->epd); //Enabled? Leave now if not. // if(!p->enabled) return; - if(!params->epd.enabled) { + if (!params->epd.enabled) { return; } - if(params->wavelet.enabled && params->wavelet.tmrs != 0) { + if (params->wavelet.enabled && params->wavelet.tmrs != 0) { return; } @@ -6484,7 +6519,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) float *a = lab->a[0]; float *b = lab->b[0]; size_t N = lab->W * lab->H; - EdgePreservingDecomposition epd(lab->W, lab->H); + EdgePreservingDecomposition epd (lab->W, lab->H); //Due to the taking of logarithms, L must be nonnegative. Further, scale to 0 to 1 using nominal range of L, 0 to 15 bit. float minL = FLT_MAX; @@ -6495,35 +6530,35 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) float lmaxL = 0.f; #pragma omp for - for(size_t i = 0; i < N; i++) { - if(L[i] < lminL) { + for (size_t i = 0; i < N; i++) { + if (L[i] < lminL) { lminL = L[i]; } - if(L[i] > lmaxL) { + if (L[i] > lmaxL) { lmaxL = L[i]; } } #pragma omp critical { - if(lminL < minL) { + if (lminL < minL) { minL = lminL; } - if(lmaxL > maxL) { + if (lmaxL > maxL) { maxL = lmaxL; } } } - if(minL > 0.0f) { + if (minL > 0.0f) { minL = 0.0f; //Disable the shift if there are no negative numbers. I wish there were just no negative numbers to begin with. } #pragma omp parallel for - for(size_t i = 0; i < N; ++i) + for (size_t i = 0; i < N; ++i) //{L[i] = (L[i] - minL)/32767.0f; { L[i] = (L[i] - minL) / maxL; @@ -6531,16 +6566,16 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) } //Some interpretations. - float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. + float Compression = expf (-stren); //This modification turns numbers symmetric around 0 into exponents. float DetailBoost = stren; - if(stren < 0.0f) { + if (stren < 0.0f) { DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. } //Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur. - if(Iterates == 0) { - Iterates = (unsigned int)(edgest * 15.0f); + if (Iterates == 0) { + Iterates = (unsigned int) (edgest * 15.0f); } /* Debuggery. Saves L for toying with outside of RT. @@ -6550,15 +6585,15 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) fwrite(L, N, sizeof(float), f); fclose(f);*/ - epd.CompressDynamicRange(L, sca / float(skip), edgest, Compression, DetailBoost, Iterates, rew, L); + epd.CompressDynamicRange (L, sca / float (skip), edgest, Compression, DetailBoost, Iterates, rew, L); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. - float s = (1.0f + 38.7889f) * powf(Compression, 1.5856f) / (1.0f + 38.7889f * powf(Compression, 1.5856f)); + float s = (1.0f + 38.7889f) * powf (Compression, 1.5856f) / (1.0f + 38.7889f * powf (Compression, 1.5856f)); #ifdef _OPENMP #pragma omp parallel for // removed schedule(dynamic,10) #endif - for(size_t ii = 0; ii < N; ++ii) { + for (size_t ii = 0; ii < N; ++ii) { a[ii] *= s; b[ii] *= s; L[ii] = L[ii] * maxL * (1.f / gamm) + minL; @@ -6579,7 +6614,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double float ave = 0.f, hidev = 0.f, lodev = 0.f; //find average luminance - histogram.getSumAndAverage(sum, ave); + histogram.getSumAndAverage (sum, ave); //find median of luminance int median = 0, count = histogram[0]; @@ -6606,18 +6641,18 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double int i = 0; - for (; i < min((int)ave, imax); i++) { + for (; i < min ((int)ave, imax); i++) { if (count < 8) { octile[count] += histogram[i]; if (octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f)) { - octile[count] = xlog(1. + (float)i) / log(2.f); + octile[count] = xlog (1. + (float)i) / log (2.f); count++;// = min(count+1,7); } } //lodev += SQR(ave-i)*histogram[i]; - lodev += (xlog(ave + 1.f) - xlog((float)i + 1.)) * histogram[i]; + lodev += (xlog (ave + 1.f) - xlog ((float)i + 1.)) * histogram[i]; losum += histogram[i]; } @@ -6626,13 +6661,13 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double octile[count] += histogram[i]; if (octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f)) { - octile[count] = xlog(1. + (float)i) / log(2.f); + octile[count] = xlog (1. + (float)i) / log (2.f); count++;// = min(count+1,7); } } //hidev += SQR(i-ave)*histogram[i]; - hidev += (xlog((float)i + 1.) - xlog(ave + 1.f)) * histogram[i]; + hidev += (xlog ((float)i + 1.) - xlog (ave + 1.f)) * histogram[i]; hisum += histogram[i]; } @@ -6650,12 +6685,12 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double // lodev = (lodev / (log(2.f) * losum)); // hidev = (hidev / (log(2.f) * hisum)); - if (octile[6] > log1p((float)imax) / log2(2.f)) { //if very overxposed image + if (octile[6] > log1p ((float)imax) / log2 (2.f)) { //if very overxposed image octile[6] = 1.5f * octile[5] - 0.5f * octile[4]; overex = 2; } - if (octile[7] > log1p((float)imax) / log2(2.f)) { //if overexposed + if (octile[7] > log1p ((float)imax) / log2 (2.f)) { //if overexposed octile[7] = 1.5f * octile[6] - 0.5f * octile[5]; overex = 1; } @@ -6668,7 +6703,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double oct7 = octile[7]; - for(int i = 1; i < 8; i++) { + for (int i = 1; i < 8; i++) { if (octile[i] == 0.0f) { octile[i] = octile[i - 1]; } @@ -6677,7 +6712,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double // compute weighted average separation of octiles // for future use in contrast setting for (int i = 1; i < 6; i++) { - ospread += (octile[i + 1] - octile[i]) / max(0.5f, (i > 2 ? (octile[i + 1] - octile[3]) : (octile[3] - octile[i]))); + ospread += (octile[i + 1] - octile[i]) / max (0.5f, (i > 2 ? (octile[i + 1] - octile[3]) : (octile[3] - octile[i]))); } ospread /= 5.f; @@ -6703,7 +6738,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double } //compute clipped white point - unsigned int clippable = (int)(sum * clip / 100.f ); + unsigned int clippable = (int) (sum * clip / 100.f ); clipped = 0; int whiteclip = (imax) - 1; @@ -6737,24 +6772,24 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double //sets the mean or median at middle gray, and the amount that sets the estimated top //of the histogram at or near clipping. //float expcomp1 = (log(/*(median/ave)*//*(hidev/lodev)*/midgray*scale/(ave-shc+midgray*shc))+log((hidev/lodev)))/log(2.f); - float expcomp1 = (log(/*(median/ave)*//*(hidev/lodev)*/midgray * scale / (ave - shc + midgray * shc))) / log(2.f); + float expcomp1 = (log (/*(median/ave)*//*(hidev/lodev)*/midgray * scale / (ave - shc + midgray * shc))) / log (2.f); float expcomp2; - if(overex == 0) { // image is not overexposed - expcomp2 = 0.5f * ( (15.5f - histcompr - (2.f * oct7 - oct6)) + log(scale / rawmax) / log(2.f) ); + if (overex == 0) { // image is not overexposed + expcomp2 = 0.5f * ( (15.5f - histcompr - (2.f * oct7 - oct6)) + log (scale / rawmax) / log (2.f) ); } else { - expcomp2 = 0.5f * ( (15.5f - histcompr - (2.f * octile[7] - octile[6])) + log(scale / rawmax) / log(2.f) ); + expcomp2 = 0.5f * ( (15.5f - histcompr - (2.f * octile[7] - octile[6])) + log (scale / rawmax) / log (2.f) ); } - if(fabs(expcomp1) - fabs(expcomp2) > 1.f) { //for great expcomp - expcomp = (expcomp1 * fabs(expcomp2) + expcomp2 * fabs(expcomp1)) / (fabs(expcomp1) + fabs(expcomp2)); + if (fabs (expcomp1) - fabs (expcomp2) > 1.f) { //for great expcomp + expcomp = (expcomp1 * fabs (expcomp2) + expcomp2 * fabs (expcomp1)) / (fabs (expcomp1) + fabs (expcomp2)); } else { expcomp = 0.5 * (double)expcomp1 + 0.5 * (double) expcomp2; //for small expcomp } - float gain = exp((float)expcomp * log(2.f)); + float gain = exp ((float)expcomp * log (2.f)); - float corr = sqrt(gain * scale / rawmax); + float corr = sqrt (gain * scale / rawmax); black = (int) shc * corr; @@ -6763,12 +6798,12 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double //this is a series approximation of the actual formula for comp, //which is a transcendental equation float comp = (gain * ((float)whiteclip) / scale - 1.f) * 2.3f; // 2.3 instead of 2 to increase slightly comp - hlcompr = (int)(100.*comp / (max(0.0, expcomp) + 1.0)); - hlcompr = max(0, min(100, hlcompr)); + hlcompr = (int) (100.*comp / (max (0.0, expcomp) + 1.0)); + hlcompr = max (0, min (100, hlcompr)); //now find brightness if gain didn't bring ave to midgray using //the envelope of the actual 'control cage' brightness curve for simplicity - float midtmp = gain * sqrt(median * ave) / scale; + float midtmp = gain * sqrt (median * ave) / scale; if (midtmp < 0.1f) { bright = (midgray - midtmp) * 15.0 / (midtmp); @@ -6776,13 +6811,13 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double bright = (midgray - midtmp) * 15.0 / (0.10833 - 0.0833 * midtmp); } - bright = 0.25 */*(median/ave)*(hidev/lodev)*/max(0, bright); + bright = 0.25 */*(median/ave)*(hidev/lodev)*/max (0, bright); //compute contrast that spreads the average spacing of octiles contr = (int) 50.0f * (1.1f - ospread); - contr = max(0, min(100, contr)); + contr = max (0, min (100, contr)); //take gamma into account - double whiteclipg = (int)(CurveFactory::gamma2 (whiteclip * corr / 65536.0) * 65536.0); + double whiteclipg = (int) (CurveFactory::gamma2 (whiteclip * corr / 65536.0) * 65536.0); float gavg = 0.; @@ -6804,10 +6839,10 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double } } - whiteclipg = CurveFactory::igamma2 ((float)(whiteclipg / 65535.0)) * 65535.0; //need to inverse gamma transform to get correct exposure compensation parameter + whiteclipg = CurveFactory::igamma2 ((float) (whiteclipg / 65535.0)) * 65535.0; //need to inverse gamma transform to get correct exposure compensation parameter //corection with gamma - black = (int)((65535 * black) / whiteclipg); + black = (int) ((65535 * black) / whiteclipg); //expcomp = log(65535.0 / (whiteclipg)) / log(2.0); //diagnostics @@ -6863,7 +6898,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double expcomp = 12.0; } - bright = max(-100, min(bright, 100)); + bright = max (-100, min (bright, 100)); } @@ -6926,7 +6961,7 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si double dist_amount; int dist_result = calcDistortion (thumbGray, rawGray, width, h_thumb, 1, dist_amount); - if(dist_result == -1) { // not enough features found, try increasing max. number of features by factor 4 + if (dist_result == -1) { // not enough features found, try increasing max. number of features by factor 4 calcDistortion (thumbGray, rawGray, width, h_thumb, 4, dist_amount); } @@ -6940,13 +6975,13 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si } } -void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace) +void ImProcFunctions::rgb2lab (const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace) { - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix( workingSpace ); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix ( workingSpace ); const float wp[3][3] = { - {static_cast<float>(wprof[0][0]), static_cast<float>(wprof[0][1]), static_cast<float>(wprof[0][2])}, - {static_cast<float>(wprof[1][0]), static_cast<float>(wprof[1][1]), static_cast<float>(wprof[1][2])}, - {static_cast<float>(wprof[2][0]), static_cast<float>(wprof[2][1]), static_cast<float>(wprof[2][2])} + {static_cast<float> (wprof[0][0]), static_cast<float> (wprof[0][1]), static_cast<float> (wprof[0][2])}, + {static_cast<float> (wprof[1][0]), static_cast<float> (wprof[1][1]), static_cast<float> (wprof[1][2])}, + {static_cast<float> (wprof[2][0]), static_cast<float> (wprof[2][1]), static_cast<float> (wprof[2][2])} }; const int W = src.getWidth(); @@ -6956,23 +6991,23 @@ void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib:: #pragma omp parallel for schedule(dynamic,16) #endif - for(int i = 0; i < H; i++) { - for(int j = 0; j < W; j++) { + for (int i = 0; i < H; i++) { + for (int j = 0; j < W; j++) { float X, Y, Z; - Color::rgbxyz(src.r(i, j), src.g(i, j), src.b(i, j), X, Y, Z, wp); + Color::rgbxyz (src.r (i, j), src.g (i, j), src.b (i, j), X, Y, Z, wp); //convert Lab - Color::XYZ2Lab(X, Y, Z, dst.L[i][j], dst.a[i][j], dst.b[i][j]); + Color::XYZ2Lab (X, Y, Z, dst.L[i][j], dst.a[i][j], dst.b[i][j]); } } } -SSEFUNCTION void ImProcFunctions::lab2rgb(const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace) +SSEFUNCTION void ImProcFunctions::lab2rgb (const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace) { - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix( workingSpace ); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix ( workingSpace ); const float wip[3][3] = { - {static_cast<float>(wiprof[0][0]), static_cast<float>(wiprof[0][1]), static_cast<float>(wiprof[0][2])}, - {static_cast<float>(wiprof[1][0]), static_cast<float>(wiprof[1][1]), static_cast<float>(wiprof[1][2])}, - {static_cast<float>(wiprof[2][0]), static_cast<float>(wiprof[2][1]), static_cast<float>(wiprof[2][2])} + {static_cast<float> (wiprof[0][0]), static_cast<float> (wiprof[0][1]), static_cast<float> (wiprof[0][2])}, + {static_cast<float> (wiprof[1][0]), static_cast<float> (wiprof[1][1]), static_cast<float> (wiprof[1][2])}, + {static_cast<float> (wiprof[2][0]), static_cast<float> (wiprof[2][1]), static_cast<float> (wiprof[2][2])} }; const int W = dst.getWidth(); @@ -6980,9 +7015,9 @@ SSEFUNCTION void ImProcFunctions::lab2rgb(const LabImage &src, Imagefloat &dst, #ifdef __SSE2__ vfloat wipv[3][3]; - for(int i = 0; i < 3; i++) { - for(int j = 0; j < 3; j++) { - wipv[i][j] = F2V(wiprof[i][j]); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + wipv[i][j] = F2V (wiprof[i][j]); } } @@ -6992,26 +7027,26 @@ SSEFUNCTION void ImProcFunctions::lab2rgb(const LabImage &src, Imagefloat &dst, #pragma omp parallel for schedule(dynamic,16) #endif - for(int i = 0; i < H; i++) { + for (int i = 0; i < H; i++) { int j = 0; #ifdef __SSE2__ - for(; j < W - 3; j += 4) { + for (; j < W - 3; j += 4) { vfloat X, Y, Z; vfloat R, G, B; - Color::Lab2XYZ(LVFU(src.L[i][j]), LVFU(src.a[i][j]), LVFU(src.b[i][j]), X, Y, Z); - Color::xyz2rgb(X, Y, Z, R, G, B, wipv); - STVFU(dst.r(i, j), R); - STVFU(dst.g(i, j), G); - STVFU(dst.b(i, j), B); + Color::Lab2XYZ (LVFU (src.L[i][j]), LVFU (src.a[i][j]), LVFU (src.b[i][j]), X, Y, Z); + Color::xyz2rgb (X, Y, Z, R, G, B, wipv); + STVFU (dst.r (i, j), R); + STVFU (dst.g (i, j), G); + STVFU (dst.b (i, j), B); } #endif - for(; j < W; j++) { + for (; j < W; j++) { float X, Y, Z; - Color::Lab2XYZ(src.L[i][j], src.a[i][j], src.b[i][j], X, Y, Z); - Color::xyz2rgb(X, Y, Z, dst.r(i, j), dst.g(i, j), dst.b(i, j), wip); + Color::Lab2XYZ (src.L[i][j], src.a[i][j], src.b[i][j], X, Y, Z); + Color::xyz2rgb (X, Y, Z, dst.r (i, j), dst.g (i, j), dst.b (i, j), wip); } } } diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index cdcfb10f2..59bdb4b31 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -24,12 +24,12 @@ using namespace rtengine; using namespace rtengine::procparams; -ColorAppearance::ColorAppearance () : FoldableToolPanel(this, "colorappearance", M("TP_COLORAPP_LABEL"), false, true) +ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance", M ("TP_COLORAPP_LABEL"), false, true) { - CurveListener::setMulti(true); + CurveListener::setMulti (true); std::vector<GradientMilestone> milestones; - milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); - milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + milestones.push_back ( GradientMilestone (0., 0., 0., 0.) ); + milestones.push_back ( GradientMilestone (1., 1., 1., 1.) ); // ------------------------ Process #1: Converting to CIECAM @@ -40,51 +40,51 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel(this, "colorappearance", // Vertical box container for the content of the Process 1 frame Gtk::VBox *p1VBox; - p1Frame = Gtk::manage (new Gtk::Frame(M("TP_COLORAPP_LABEL_SCENE")) ); - p1Frame->set_label_align(0.025, 0.5); + p1Frame = Gtk::manage (new Gtk::Frame (M ("TP_COLORAPP_LABEL_SCENE")) ); + p1Frame->set_label_align (0.025, 0.5); p1VBox = Gtk::manage ( new Gtk::VBox()); - p1VBox->set_spacing(2); + p1VBox->set_spacing (2); - degree = Gtk::manage (new Adjuster (M("TP_COLORAPP_CIECAT_DEGREE"), 0., 100., 1., 100.)); + degree = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CIECAT_DEGREE"), 0., 100., 1., 100.)); if (degree->delay < options.adjusterMaxDelay) { degree->delay = options.adjusterMaxDelay; } degree->throwOnButtonRelease(); - degree->addAutoButton(M("TP_COLORAPP_DEGREE_AUTO_TOOLTIP")); - degree->set_tooltip_markup (M("TP_COLORAPP_DEGREE_TOOLTIP")); + degree->addAutoButton (M ("TP_COLORAPP_DEGREE_AUTO_TOOLTIP")); + degree->set_tooltip_markup (M ("TP_COLORAPP_DEGREE_TOOLTIP")); p1VBox->pack_start (*degree); - surrsource = Gtk::manage (new Gtk::CheckButton (M("TP_COLORAPP_SURSOURCE"))); - surrsource->set_tooltip_markup (M("TP_COLORAPP_SURSOURCE_TOOLTIP")); + surrsource = Gtk::manage (new Gtk::CheckButton (M ("TP_COLORAPP_SURSOURCE"))); + surrsource->set_tooltip_markup (M ("TP_COLORAPP_SURSOURCE_TOOLTIP")); p1VBox->pack_start (*surrsource, Gtk::PACK_SHRINK); Gtk::HBox* wbmHBox = Gtk::manage (new Gtk::HBox ()); wbmHBox->set_spacing (2); - wbmHBox->set_tooltip_markup (M("TP_COLORAPP_MODEL_TOOLTIP")); - Gtk::Label* wbmLab = Gtk::manage (new Gtk::Label (M("TP_COLORAPP_MODEL") + ":")); + wbmHBox->set_tooltip_markup (M ("TP_COLORAPP_MODEL_TOOLTIP")); + Gtk::Label* wbmLab = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_MODEL") + ":")); wbmHBox->pack_start (*wbmLab, Gtk::PACK_SHRINK); wbmodel = Gtk::manage (new MyComboBoxText ()); - wbmodel->append (M("TP_COLORAPP_WBRT")); - wbmodel->append (M("TP_COLORAPP_WBCAM")); + wbmodel->append (M ("TP_COLORAPP_WBRT")); + wbmodel->append (M ("TP_COLORAPP_WBCAM")); wbmodel->set_active (0); wbmHBox->pack_start (*wbmodel); p1VBox->pack_start (*wbmHBox); - adapscen = Gtk::manage (new Adjuster (M("TP_COLORAPP_ADAPTSCENE"), 0.001, 16384., 0.001, 2000.));// EV -7 ==> EV 17 + adapscen = Gtk::manage (new Adjuster (M ("TP_COLORAPP_ADAPTSCENE"), 0.001, 16384., 0.001, 2000.)); // EV -7 ==> EV 17 if (adapscen->delay < options.adjusterMaxDelay) { adapscen->delay = options.adjusterMaxDelay; } adapscen->throwOnButtonRelease(); - adapscen->addAutoButton(M("TP_COLORAPP_ADAP_AUTO_TOOLTIP")); - adapscen->set_tooltip_markup (M("TP_COLORAPP_ADAPTSCENE_TOOLTIP")); + adapscen->addAutoButton (M ("TP_COLORAPP_ADAP_AUTO_TOOLTIP")); + adapscen->set_tooltip_markup (M ("TP_COLORAPP_ADAPTSCENE_TOOLTIP")); p1VBox->pack_start (*adapscen); - p1Frame->add(*p1VBox); + p1Frame->add (*p1VBox); pack_start (*p1Frame, Gtk::PACK_EXPAND_WIDGET, 4); @@ -96,123 +96,123 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel(this, "colorappearance", // Vertical box container for the content of the Process 1 frame Gtk::VBox *p2VBox; - p2Frame = Gtk::manage (new Gtk::Frame(M("TP_COLORAPP_LABEL_CAM02")) ); - p2Frame->set_label_align(0.025, 0.5); + p2Frame = Gtk::manage (new Gtk::Frame (M ("TP_COLORAPP_LABEL_CAM02")) ); + p2Frame->set_label_align (0.025, 0.5); p2VBox = Gtk::manage ( new Gtk::VBox()); - p2VBox->set_spacing(2); + p2VBox->set_spacing (2); Gtk::HBox* alHBox = Gtk::manage (new Gtk::HBox ()); alHBox->set_spacing (2); - alHBox->set_tooltip_markup (M("TP_COLORAPP_ALGO_TOOLTIP")); - Gtk::Label* alLabel = Gtk::manage (new Gtk::Label (M("TP_COLORAPP_ALGO") + ":")); + alHBox->set_tooltip_markup (M ("TP_COLORAPP_ALGO_TOOLTIP")); + Gtk::Label* alLabel = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_ALGO") + ":")); alHBox->pack_start (*alLabel, Gtk::PACK_SHRINK); algo = Gtk::manage (new MyComboBoxText ()); - algo->append (M("TP_COLORAPP_ALGO_JC")); - algo->append (M("TP_COLORAPP_ALGO_JS")); - algo->append (M("TP_COLORAPP_ALGO_QM")); - algo->append (M("TP_COLORAPP_ALGO_ALL")); + algo->append (M ("TP_COLORAPP_ALGO_JC")); + algo->append (M ("TP_COLORAPP_ALGO_JS")); + algo->append (M ("TP_COLORAPP_ALGO_QM")); + algo->append (M ("TP_COLORAPP_ALGO_ALL")); algo->set_active (0); alHBox->pack_start (*algo); p2VBox->pack_start (*alHBox); p2VBox->pack_start (*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET, 4); - jlight = Gtk::manage (new Adjuster (M("TP_COLORAPP_LIGHT"), -100.0, 100.0, 0.1, 0.)); + jlight = Gtk::manage (new Adjuster (M ("TP_COLORAPP_LIGHT"), -100.0, 100.0, 0.1, 0.)); if (jlight->delay < options.adjusterMaxDelay) { jlight->delay = options.adjusterMaxDelay; } jlight->throwOnButtonRelease(); - jlight->set_tooltip_markup (M("TP_COLORAPP_LIGHT_TOOLTIP")); + jlight->set_tooltip_markup (M ("TP_COLORAPP_LIGHT_TOOLTIP")); p2VBox->pack_start (*jlight); - qbright = Gtk::manage (new Adjuster (M("TP_COLORAPP_BRIGHT"), -100.0, 100.0, 0.1, 0.)); + qbright = Gtk::manage (new Adjuster (M ("TP_COLORAPP_BRIGHT"), -100.0, 100.0, 0.1, 0.)); if (qbright->delay < options.adjusterMaxDelay) { qbright->delay = options.adjusterMaxDelay; } qbright->throwOnButtonRelease(); - qbright->set_tooltip_markup (M("TP_COLORAPP_BRIGHT_TOOLTIP")); + qbright->set_tooltip_markup (M ("TP_COLORAPP_BRIGHT_TOOLTIP")); p2VBox->pack_start (*qbright); - chroma = Gtk::manage (new Adjuster (M("TP_COLORAPP_CHROMA"), -100.0, 100.0, 0.1, 0.)); + chroma = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CHROMA"), -100.0, 100.0, 0.1, 0.)); if (chroma->delay < options.adjusterMaxDelay) { chroma->delay = options.adjusterMaxDelay; } chroma->throwOnButtonRelease(); - chroma->set_tooltip_markup (M("TP_COLORAPP_CHROMA_TOOLTIP")); + chroma->set_tooltip_markup (M ("TP_COLORAPP_CHROMA_TOOLTIP")); p2VBox->pack_start (*chroma); - schroma = Gtk::manage (new Adjuster (M("TP_COLORAPP_CHROMA_S"), -100.0, 100.0, 0.1, 0.)); + schroma = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CHROMA_S"), -100.0, 100.0, 0.1, 0.)); if (schroma->delay < options.adjusterMaxDelay) { schroma->delay = options.adjusterMaxDelay; } schroma->throwOnButtonRelease(); - schroma->set_tooltip_markup (M("TP_COLORAPP_CHROMA_S_TOOLTIP")); + schroma->set_tooltip_markup (M ("TP_COLORAPP_CHROMA_S_TOOLTIP")); p2VBox->pack_start (*schroma); - mchroma = Gtk::manage (new Adjuster (M("TP_COLORAPP_CHROMA_M"), -100.0, 100.0, 0.1, 0.)); + mchroma = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CHROMA_M"), -100.0, 100.0, 0.1, 0.)); if (mchroma->delay < options.adjusterMaxDelay) { mchroma->delay = options.adjusterMaxDelay; } mchroma->throwOnButtonRelease(); - mchroma->set_tooltip_markup (M("TP_COLORAPP_CHROMA_M_TOOLTIP")); + mchroma->set_tooltip_markup (M ("TP_COLORAPP_CHROMA_M_TOOLTIP")); p2VBox->pack_start (*mchroma); - rstprotection = Gtk::manage ( new Adjuster (M("TP_COLORAPP_RSTPRO"), 0., 100., 0.1, 0.) ); + rstprotection = Gtk::manage ( new Adjuster (M ("TP_COLORAPP_RSTPRO"), 0., 100., 0.1, 0.) ); if (rstprotection->delay < options.adjusterMaxDelay) { rstprotection->delay = options.adjusterMaxDelay; } rstprotection->throwOnButtonRelease(); - rstprotection->set_tooltip_markup (M("TP_COLORAPP_RSTPRO_TOOLTIP")); + rstprotection->set_tooltip_markup (M ("TP_COLORAPP_RSTPRO_TOOLTIP")); p2VBox->pack_start (*rstprotection); - contrast = Gtk::manage (new Adjuster (M("TP_COLORAPP_CONTRAST"), -100.0, 100.0, 0.1, 0.)); + contrast = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CONTRAST"), -100.0, 100.0, 0.1, 0.)); if (contrast->delay < options.adjusterMaxDelay) { contrast->delay = options.adjusterMaxDelay; } contrast->throwOnButtonRelease(); - contrast->set_tooltip_markup (M("TP_COLORAPP_CONTRAST_TOOLTIP")); + contrast->set_tooltip_markup (M ("TP_COLORAPP_CONTRAST_TOOLTIP")); p2VBox->pack_start (*contrast); - qcontrast = Gtk::manage (new Adjuster (M("TP_COLORAPP_CONTRAST_Q"), -100.0, 100.0, 0.1, 0.)); + qcontrast = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CONTRAST_Q"), -100.0, 100.0, 0.1, 0.)); if (qcontrast->delay < options.adjusterMaxDelay) { qcontrast->delay = options.adjusterMaxDelay; } qcontrast->throwOnButtonRelease(); - qcontrast->set_tooltip_markup (M("TP_COLORAPP_CONTRAST_Q_TOOLTIP")); + qcontrast->set_tooltip_markup (M ("TP_COLORAPP_CONTRAST_Q_TOOLTIP")); p2VBox->pack_start (*qcontrast); - colorh = Gtk::manage (new Adjuster (M("TP_COLORAPP_HUE"), -100.0, 100.0, 0.1, 0.)); + colorh = Gtk::manage (new Adjuster (M ("TP_COLORAPP_HUE"), -100.0, 100.0, 0.1, 0.)); if (colorh->delay < options.adjusterMaxDelay) { colorh->delay = options.adjusterMaxDelay; } colorh->throwOnButtonRelease(); - colorh->set_tooltip_markup (M("TP_COLORAPP_HUE_TOOLTIP")); + colorh->set_tooltip_markup (M ("TP_COLORAPP_HUE_TOOLTIP")); p2VBox->pack_start (*colorh); - tonecie = Gtk::manage (new Gtk::CheckButton (M("TP_COLORAPP_TONECIE"))); - tonecie->set_tooltip_markup (M("TP_COLORAPP_TONECIE_TOOLTIP")); - tonecieconn = tonecie->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::tonecie_toggled) ); + tonecie = Gtk::manage (new Gtk::CheckButton (M ("TP_COLORAPP_TONECIE"))); + tonecie->set_tooltip_markup (M ("TP_COLORAPP_TONECIE_TOOLTIP")); + tonecieconn = tonecie->signal_toggled().connect ( sigc::mem_fun (*this, &ColorAppearance::tonecie_toggled) ); p2VBox->pack_start (*tonecie); /* sharpcie = Gtk::manage (new Gtk::CheckButton (M("TP_COLORAPP_SHARPCIE"))); @@ -223,52 +223,52 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel(this, "colorappearance", p2VBox->pack_start (*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET, 4); toneCurveMode = Gtk::manage (new MyComboBoxText ()); - toneCurveMode->append (M("TP_COLORAPP_TCMODE_LIGHTNESS")); - toneCurveMode->append (M("TP_COLORAPP_TCMODE_BRIGHTNESS")); + toneCurveMode->append (M ("TP_COLORAPP_TCMODE_LIGHTNESS")); + toneCurveMode->append (M ("TP_COLORAPP_TCMODE_BRIGHTNESS")); toneCurveMode->set_active (0); - toneCurveMode->set_tooltip_text(M("TP_COLORAPP_TCMODE_LABEL1")); + toneCurveMode->set_tooltip_text (M ("TP_COLORAPP_TCMODE_LABEL1")); - curveEditorG = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_COLORAPP_CURVEEDITOR1")); + curveEditorG = new CurveEditorGroup (options.lastToneCurvesDir, M ("TP_COLORAPP_CURVEEDITOR1")); curveEditorG->setCurveListener (this); - curveEditorG->setTooltip(M("TP_COLORAPP_CURVEEDITOR1_TOOLTIP")); + curveEditorG->setTooltip (M ("TP_COLORAPP_CURVEEDITOR1_TOOLTIP")); - shape = static_cast<DiagonalCurveEditor*>(curveEditorG->addCurve(CT_Diagonal, "", toneCurveMode)); + shape = static_cast<DiagonalCurveEditor*> (curveEditorG->addCurve (CT_Diagonal, "", toneCurveMode)); - tcmodeconn = toneCurveMode->signal_changed().connect( sigc::mem_fun(*this, &ColorAppearance::curveMode1Changed), true ); + tcmodeconn = toneCurveMode->signal_changed().connect ( sigc::mem_fun (*this, &ColorAppearance::curveMode1Changed), true ); toneCurveMode2 = Gtk::manage (new MyComboBoxText ()); - toneCurveMode2->append (M("TP_COLORAPP_TCMODE_LIGHTNESS")); - toneCurveMode2->append (M("TP_COLORAPP_TCMODE_BRIGHTNESS")); + toneCurveMode2->append (M ("TP_COLORAPP_TCMODE_LIGHTNESS")); + toneCurveMode2->append (M ("TP_COLORAPP_TCMODE_BRIGHTNESS")); toneCurveMode2->set_active (0); - toneCurveMode2->set_tooltip_text(M("TP_COLORAPP_TCMODE_LABEL2")); + toneCurveMode2->set_tooltip_text (M ("TP_COLORAPP_TCMODE_LABEL2")); - curveEditorG2 = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_COLORAPP_CURVEEDITOR2")); + curveEditorG2 = new CurveEditorGroup (options.lastToneCurvesDir, M ("TP_COLORAPP_CURVEEDITOR2")); curveEditorG2->setCurveListener (this); - shape2 = static_cast<DiagonalCurveEditor*>(curveEditorG2->addCurve(CT_Diagonal, "", toneCurveMode2)); + shape2 = static_cast<DiagonalCurveEditor*> (curveEditorG2->addCurve (CT_Diagonal, "", toneCurveMode2)); - tcmode2conn = toneCurveMode2->signal_changed().connect( sigc::mem_fun(*this, &ColorAppearance::curveMode2Changed), true ); + tcmode2conn = toneCurveMode2->signal_changed().connect ( sigc::mem_fun (*this, &ColorAppearance::curveMode2Changed), true ); toneCurveMode3 = Gtk::manage (new MyComboBoxText ()); - toneCurveMode3->append (M("TP_COLORAPP_TCMODE_CHROMA")); - toneCurveMode3->append (M("TP_COLORAPP_TCMODE_SATUR")); - toneCurveMode3->append (M("TP_COLORAPP_TCMODE_COLORF")); + toneCurveMode3->append (M ("TP_COLORAPP_TCMODE_CHROMA")); + toneCurveMode3->append (M ("TP_COLORAPP_TCMODE_SATUR")); + toneCurveMode3->append (M ("TP_COLORAPP_TCMODE_COLORF")); toneCurveMode3->set_active (0); - toneCurveMode3->set_tooltip_text(M("TP_COLORAPP_TCMODE_LABEL3")); + toneCurveMode3->set_tooltip_text (M ("TP_COLORAPP_TCMODE_LABEL3")); - curveEditorG3 = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_COLORAPP_CURVEEDITOR3")); + curveEditorG3 = new CurveEditorGroup (options.lastToneCurvesDir, M ("TP_COLORAPP_CURVEEDITOR3")); curveEditorG3->setCurveListener (this); - shape3 = static_cast<DiagonalCurveEditor*>(curveEditorG3->addCurve(CT_Diagonal, "", toneCurveMode3)); - shape3->setRangeLabels( - M("TP_LABCURVE_CURVEEDITOR_CC_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE2"), - M("TP_LABCURVE_CURVEEDITOR_CC_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE4") + shape3 = static_cast<DiagonalCurveEditor*> (curveEditorG3->addCurve (CT_Diagonal, "", toneCurveMode3)); + shape3->setRangeLabels ( + M ("TP_LABCURVE_CURVEEDITOR_CC_RANGE1"), M ("TP_LABCURVE_CURVEEDITOR_CC_RANGE2"), + M ("TP_LABCURVE_CURVEEDITOR_CC_RANGE3"), M ("TP_LABCURVE_CURVEEDITOR_CC_RANGE4") ); - shape3->setBottomBarColorProvider(this, 1); - shape3->setLeftBarColorProvider(this, 1); - shape3->setRangeDefaultMilestones(0.05, 0.2, 0.58); + shape3->setBottomBarColorProvider (this, 1); + shape3->setLeftBarColorProvider (this, 1); + shape3->setRangeDefaultMilestones (0.05, 0.2, 0.58); // shape3->setBottomBarColorProvider(this, 2); @@ -278,51 +278,51 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel(this, "colorappearance", // The milestones are still the same than those define above //milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); //milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); - shape->setBottomBarBgGradient(milestones); - shape->setLeftBarBgGradient(milestones); - shape2->setBottomBarBgGradient(milestones); - shape2->setLeftBarBgGradient(milestones); + shape->setBottomBarBgGradient (milestones); + shape->setLeftBarBgGradient (milestones); + shape2->setBottomBarBgGradient (milestones); + shape2->setLeftBarBgGradient (milestones); std::vector<GradientMilestone> shape3Milestones; float R, G, B; for (int i = 0; i < 7; i++) { - float x = float(i) * (1.0f / 6.0); - Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B); - shape3Milestones.push_back( GradientMilestone(double(x), double(R), double(G), double(B)) ); + float x = float (i) * (1.0f / 6.0); + Color::hsv2rgb01 (x, 0.5f, 0.5f, R, G, B); + shape3Milestones.push_back ( GradientMilestone (double (x), double (R), double (G), double (B)) ); } - shape3->setBottomBarBgGradient(shape3Milestones); - shape3->setLeftBarBgGradient(shape3Milestones); + shape3->setBottomBarBgGradient (shape3Milestones); + shape3->setLeftBarBgGradient (shape3Milestones); - shape3->setRangeDefaultMilestones(0.05, 0.2, 0.58); + shape3->setRangeDefaultMilestones (0.05, 0.2, 0.58); curveEditorG->curveListComplete(); curveEditorG2->curveListComplete(); - curveEditorG2->setTooltip(M("TP_COLORAPP_CURVEEDITOR2_TOOLTIP")); + curveEditorG2->setTooltip (M ("TP_COLORAPP_CURVEEDITOR2_TOOLTIP")); curveEditorG3->curveListComplete(); - curveEditorG3->setTooltip(M("TP_COLORAPP_CURVEEDITOR3_TOOLTIP")); - tcmode3conn = toneCurveMode3->signal_changed().connect( sigc::mem_fun(*this, &ColorAppearance::curveMode3Changed), true ); + curveEditorG3->setTooltip (M ("TP_COLORAPP_CURVEEDITOR3_TOOLTIP")); + tcmode3conn = toneCurveMode3->signal_changed().connect ( sigc::mem_fun (*this, &ColorAppearance::curveMode3Changed), true ); - p2VBox->pack_start( *curveEditorG, Gtk::PACK_SHRINK, 2); - p2VBox->pack_start( *curveEditorG2, Gtk::PACK_SHRINK, 2); - p2VBox->pack_start( *curveEditorG3, Gtk::PACK_SHRINK, 2); + p2VBox->pack_start ( *curveEditorG, Gtk::PACK_SHRINK, 2); + p2VBox->pack_start ( *curveEditorG2, Gtk::PACK_SHRINK, 2); + p2VBox->pack_start ( *curveEditorG3, Gtk::PACK_SHRINK, 2); // ------------------------ Choice CIECAM data - datacie = Gtk::manage (new Gtk::CheckButton (M("TP_COLORAPP_DATACIE"))); - datacie->set_tooltip_markup (M("TP_COLORAPP_DATACIE_TOOLTIP")); - datacieconn = datacie->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::datacie_toggled) ); + datacie = Gtk::manage (new Gtk::CheckButton (M ("TP_COLORAPP_DATACIE"))); + datacie->set_tooltip_markup (M ("TP_COLORAPP_DATACIE_TOOLTIP")); + datacieconn = datacie->signal_toggled().connect ( sigc::mem_fun (*this, &ColorAppearance::datacie_toggled) ); p2VBox->pack_start (*datacie); //------------------------- - p2Frame->add(*p2VBox); + p2Frame->add (*p2VBox); pack_start (*p2Frame, Gtk::PACK_EXPAND_WIDGET, 4); @@ -337,46 +337,46 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel(this, "colorappearance", // Vertical box container for the content of the Process 3 frame Gtk::VBox *p3VBox; - p3Frame = Gtk::manage (new Gtk::Frame(M("TP_COLORAPP_LABEL_VIEWING")) ); // "Editing viewing conditions" ??? - p3Frame->set_label_align(0.025, 0.5); + p3Frame = Gtk::manage (new Gtk::Frame (M ("TP_COLORAPP_LABEL_VIEWING")) ); // "Editing viewing conditions" ??? + p3Frame->set_label_align (0.025, 0.5); p3VBox = Gtk::manage ( new Gtk::VBox()); - p3VBox->set_spacing(2); + p3VBox->set_spacing (2); - adaplum = Gtk::manage (new Adjuster (M("TP_COLORAPP_ADAPTVIEWING"), 0.1, 1000., 0.1, 16.)); + adaplum = Gtk::manage (new Adjuster (M ("TP_COLORAPP_ADAPTVIEWING"), 0.1, 1000., 0.1, 16.)); if (adaplum->delay < options.adjusterMaxDelay) { adaplum->delay = options.adjusterMaxDelay; } adaplum->throwOnButtonRelease(); - adaplum->set_tooltip_markup (M("TP_COLORAPP_ADAPTVIEWING_TOOLTIP")); + adaplum->set_tooltip_markup (M ("TP_COLORAPP_ADAPTVIEWING_TOOLTIP")); p3VBox->pack_start (*adaplum); Gtk::HBox* surrHBox = Gtk::manage (new Gtk::HBox ()); surrHBox->set_spacing (2); - surrHBox->set_tooltip_markup(M("TP_COLORAPP_SURROUND_TOOLTIP")); - Gtk::Label* surrLabel = Gtk::manage (new Gtk::Label (M("TP_COLORAPP_SURROUND") + ":")); + surrHBox->set_tooltip_markup (M ("TP_COLORAPP_SURROUND_TOOLTIP")); + Gtk::Label* surrLabel = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_SURROUND") + ":")); surrHBox->pack_start (*surrLabel, Gtk::PACK_SHRINK); surround = Gtk::manage (new MyComboBoxText ()); - surround->append (M("TP_COLORAPP_SURROUND_AVER")); - surround->append (M("TP_COLORAPP_SURROUND_DIM")); - surround->append (M("TP_COLORAPP_SURROUND_DARK")); - surround->append (M("TP_COLORAPP_SURROUND_EXDARK")); + surround->append (M ("TP_COLORAPP_SURROUND_AVER")); + surround->append (M ("TP_COLORAPP_SURROUND_DIM")); + surround->append (M ("TP_COLORAPP_SURROUND_DARK")); + surround->append (M ("TP_COLORAPP_SURROUND_EXDARK")); surround->set_active (1); surrHBox->pack_start (*surround); p3VBox->pack_start (*surrHBox); - p3Frame->add(*p3VBox); + p3Frame->add (*p3VBox); pack_start (*p3Frame, Gtk::PACK_EXPAND_WIDGET, 4); // ------------------------ Lab Gamut control - gamut = Gtk::manage (new Gtk::CheckButton (M("TP_COLORAPP_GAMUT"))); - gamut->set_tooltip_markup (M("TP_COLORAPP_GAMUT_TOOLTIP")); - gamutconn = gamut->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::gamut_toggled) ); + gamut = Gtk::manage (new Gtk::CheckButton (M ("TP_COLORAPP_GAMUT"))); + gamut->set_tooltip_markup (M ("TP_COLORAPP_GAMUT_TOOLTIP")); + gamutconn = gamut->signal_toggled().connect ( sigc::mem_fun (*this, &ColorAppearance::gamut_toggled) ); pack_start (*gamut, Gtk::PACK_SHRINK); // ------------------------ Bad pixel control @@ -387,23 +387,23 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel(this, "colorappearance", badpixconn = badpix->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::badpix_toggled) ); pack_start (*badpix, Gtk::PACK_SHRINK); */ - badpixsl = Gtk::manage (new Adjuster (M("TP_COLORAPP_BADPIXSL"), 0, 2, 1, 0)); + badpixsl = Gtk::manage (new Adjuster (M ("TP_COLORAPP_BADPIXSL"), 0, 2, 1, 0)); if (badpixsl->delay < options.adjusterMaxDelay) { badpixsl->delay = options.adjusterMaxDelay; } badpixsl->throwOnButtonRelease(); - badpixsl->set_tooltip_markup (M("TP_COLORAPP_BADPIXSL_TOOLTIP")); + badpixsl->set_tooltip_markup (M ("TP_COLORAPP_BADPIXSL_TOOLTIP")); pack_start (*badpixsl, Gtk::PACK_SHRINK); // ------------------------ Listening events - surrconn = surrsource->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::surrsource_toggled) ); - wbmodelconn = wbmodel->signal_changed().connect ( sigc::mem_fun(*this, &ColorAppearance::wbmodelChanged) ); - algoconn = algo->signal_changed().connect ( sigc::mem_fun(*this, &ColorAppearance::algoChanged) ); - surroundconn = surround->signal_changed().connect ( sigc::mem_fun(*this, &ColorAppearance::surroundChanged) ); + surrconn = surrsource->signal_toggled().connect ( sigc::mem_fun (*this, &ColorAppearance::surrsource_toggled) ); + wbmodelconn = wbmodel->signal_changed().connect ( sigc::mem_fun (*this, &ColorAppearance::wbmodelChanged) ); + algoconn = algo->signal_changed().connect ( sigc::mem_fun (*this, &ColorAppearance::algoChanged) ); + surroundconn = surround->signal_changed().connect ( sigc::mem_fun (*this, &ColorAppearance::surroundChanged) ); degree->setAdjusterListener (this); adapscen->setAdjusterListener (this); @@ -433,12 +433,12 @@ ColorAppearance::~ColorAppearance () -bool ColorAppearance::bgTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) +bool ColorAppearance::bgTTipQuery (int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) { return true; } -bool ColorAppearance::srTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) +bool ColorAppearance::srTTipQuery (int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) { return true; } @@ -447,15 +447,15 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); - tcmodeconn.block(true); - tcmode2conn.block(true); - tcmode3conn.block(true); + tcmodeconn.block (true); + tcmode2conn.block (true); + tcmode3conn.block (true); shape->setCurve (pp->colorappearance.curve); shape2->setCurve (pp->colorappearance.curve2); shape3->setCurve (pp->colorappearance.curve3); - toneCurveMode->set_active(pp->colorappearance.curveMode); - toneCurveMode2->set_active(pp->colorappearance.curveMode2); - toneCurveMode3->set_active(pp->colorappearance.curveMode3); + toneCurveMode->set_active (pp->colorappearance.curveMode); + toneCurveMode2->set_active (pp->colorappearance.curveMode2); + toneCurveMode3->set_active (pp->colorappearance.curveMode3); curveMode3Changed(); // This will set the correct sensitive state of depending Adjusters if (pedited) { @@ -488,23 +488,23 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) shape3->setUnChanged (!pedited->colorappearance.curve3); if (!pedited->colorappearance.curveMode) { - toneCurveMode->set_active(2); + toneCurveMode->set_active (2); } if (!pedited->colorappearance.curveMode2) { - toneCurveMode2->set_active(2); + toneCurveMode2->set_active (2); } if (!pedited->colorappearance.curveMode3) { - toneCurveMode3->set_active(3); + toneCurveMode3->set_active (3); } } - setEnabled(pp->colorappearance.enabled); + setEnabled (pp->colorappearance.enabled); - surroundconn.block(true); + surroundconn.block (true); if (pedited && !pedited->colorappearance.surround) { surround->set_active (4); @@ -518,11 +518,11 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) surround->set_active (3); } - surroundconn.block(false); + surroundconn.block (false); // Have to be manually called to handle initial state update surroundChanged(); - wbmodelconn.block(true); + wbmodelconn.block (true); if (pedited && !pedited->colorappearance.wbmodel) { wbmodel->set_active (2); @@ -532,11 +532,11 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) wbmodel->set_active (1); } - wbmodelconn.block(false); + wbmodelconn.block (false); // Have to be manually called to handle initial state update wbmodelChanged(); - algoconn.block(true); + algoconn.block (true); if (pedited && !pedited->colorappearance.algo) { algo->set_active (4); @@ -550,7 +550,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) algo->set_active (3); } - algoconn.block(false); + algoconn.block (false); // Have to be manually called to handle initial state update algoChanged(); @@ -584,7 +584,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) lastAutoAdapscen = pp->colorappearance.autoadapscen; degree->setValue (pp->colorappearance.degree); - degree->setAutoValue(pp->colorappearance.autodegree); + degree->setAutoValue (pp->colorappearance.autodegree); adapscen->setValue (pp->colorappearance.adapscen); adapscen->setAutoValue (pp->colorappearance.autoadapscen); @@ -600,9 +600,9 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) qcontrast->setValue (pp->colorappearance.qcontrast); colorh->setValue (pp->colorappearance.colorh); - tcmode3conn.block(false); - tcmode2conn.block(false); - tcmodeconn.block(false); + tcmode3conn.block (false); + tcmode2conn.block (false); + tcmodeconn.block (false); enableListener (); } void ColorAppearance::autoOpenCurve () @@ -686,9 +686,9 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) pedited->colorappearance.autodegree = !degree->getAutoInconsistent(); pedited->colorappearance.autoadapscen = !adapscen->getAutoInconsistent(); pedited->colorappearance.enabled = !get_inconsistent(); - pedited->colorappearance.surround = surround->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->colorappearance.wbmodel = wbmodel->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->colorappearance.algo = algo->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->colorappearance.surround = surround->get_active_text() != M ("GENERAL_UNCHANGED"); + pedited->colorappearance.wbmodel = wbmodel->get_active_text() != M ("GENERAL_UNCHANGED"); + pedited->colorappearance.algo = algo->get_active_text() != M ("GENERAL_UNCHANGED"); pedited->colorappearance.surrsource = !surrsource->get_inconsistent(); pedited->colorappearance.gamut = !gamut->get_inconsistent(); // pedited->colorappearance.badpix = !badpix->get_inconsistent(); @@ -735,11 +735,11 @@ void ColorAppearance::curveChanged (CurveEditor* ce) if (listener) { if (ce == shape) { - listener->panelChanged (EvCATCurve1, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvCATCurve1, M ("HISTORY_CUSTOMCURVE")); } else if (ce == shape2) { - listener->panelChanged (EvCATCurve2, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvCATCurve2, M ("HISTORY_CUSTOMCURVE")); } else if (ce == shape3) { - listener->panelChanged (EvCATCurve3, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvCATCurve3, M ("HISTORY_CUSTOMCURVE")); } } } @@ -747,7 +747,7 @@ void ColorAppearance::curveChanged (CurveEditor* ce) void ColorAppearance::curveMode1Changed () { if (listener) { - Glib::signal_idle().connect (sigc::mem_fun(*this, &ColorAppearance::curveMode1Changed_)); + Glib::signal_idle().connect (sigc::mem_fun (*this, &ColorAppearance::curveMode1Changed_)); } } @@ -763,7 +763,7 @@ bool ColorAppearance::curveMode1Changed_ () void ColorAppearance::curveMode2Changed () { if (listener) { - Glib::signal_idle().connect (sigc::mem_fun(*this, &ColorAppearance::curveMode2Changed_)); + Glib::signal_idle().connect (sigc::mem_fun (*this, &ColorAppearance::curveMode2Changed_)); } } @@ -781,18 +781,18 @@ void ColorAppearance::curveMode3Changed () int tcMode3 = toneCurveMode3->get_active_row_number(); if (tcMode3 == 0) { - chroma->set_sensitive(true); - schroma->set_sensitive(true); + chroma->set_sensitive (true); + schroma->set_sensitive (true); } else if (tcMode3 == 2) { - chroma->set_sensitive(false); - schroma->set_sensitive(false); + chroma->set_sensitive (false); + schroma->set_sensitive (false); } else if (tcMode3 == 1) { - chroma->set_sensitive(false); - schroma->set_sensitive(true); + chroma->set_sensitive (false); + schroma->set_sensitive (true); } if (listener) { - Glib::signal_idle().connect (sigc::mem_fun(*this, &ColorAppearance::curveMode3Changed_)); + Glib::signal_idle().connect (sigc::mem_fun (*this, &ColorAppearance::curveMode3Changed_)); } } @@ -823,9 +823,9 @@ void ColorAppearance::surrsource_toggled () if (listener) { if (surrsource->get_active ()) { - listener->panelChanged (EvCATsurr, M("GENERAL_ENABLED")); + listener->panelChanged (EvCATsurr, M ("GENERAL_ENABLED")); } else { - listener->panelChanged (EvCATsurr, M("GENERAL_DISABLED")); + listener->panelChanged (EvCATsurr, M ("GENERAL_DISABLED")); } } } @@ -848,9 +848,9 @@ void ColorAppearance::gamut_toggled () if (listener) { if (gamut->get_active ()) { - listener->panelChanged (EvCATgamut, M("GENERAL_ENABLED")); + listener->panelChanged (EvCATgamut, M ("GENERAL_ENABLED")); } else { - listener->panelChanged (EvCATgamut, M("GENERAL_DISABLED")); + listener->panelChanged (EvCATgamut, M ("GENERAL_DISABLED")); } } @@ -899,9 +899,9 @@ void ColorAppearance::datacie_toggled () if (listener) { if (datacie->get_active ()) { - listener->panelChanged (EvCATdatacie, M("GENERAL_ENABLED")); + listener->panelChanged (EvCATdatacie, M ("GENERAL_ENABLED")); } else { - listener->panelChanged (EvCATdatacie, M("GENERAL_DISABLED")); + listener->panelChanged (EvCATdatacie, M ("GENERAL_DISABLED")); } } } @@ -923,9 +923,9 @@ void ColorAppearance::tonecie_toggled () if (listener) { if (tonecie->get_active ()) { - listener->panelChanged (EvCATtonecie, M("GENERAL_ENABLED")); + listener->panelChanged (EvCATtonecie, M ("GENERAL_ENABLED")); } else { - listener->panelChanged (EvCATtonecie, M("GENERAL_DISABLED")); + listener->panelChanged (EvCATtonecie, M ("GENERAL_DISABLED")); } } @@ -1009,12 +1009,12 @@ void ColorAppearance::autoCamChanged (double ccam) { nextCcam = ccam; - const auto func = [](gpointer data) -> gboolean { - static_cast<ColorAppearance*>(data)->autoCamComputed_(); + const auto func = [] (gpointer data) -> gboolean { + static_cast<ColorAppearance*> (data)->autoCamComputed_(); return FALSE; }; - idle_register.add(func, this); + idle_register.add (func, this); } bool ColorAppearance::autoCamComputed_ () @@ -1032,12 +1032,12 @@ void ColorAppearance::adapCamChanged (double cadap) { nextCadap = cadap; - const auto func = [](gpointer data) -> gboolean { - static_cast<ColorAppearance*>(data)->adapCamComputed_(); + const auto func = [] (gpointer data) -> gboolean { + static_cast<ColorAppearance*> (data)->adapCamComputed_(); return FALSE; }; - idle_register.add(func, this); + idle_register.add (func, this); } bool ColorAppearance::adapCamComputed_ () @@ -1063,46 +1063,46 @@ void ColorAppearance::colorForValue (double valX, double valY, enum ColorCaller: if (callerId == 1) { // cc - bottom bar - float value = (1.f - 0.7f) * float(valX) + 0.7f; + float value = (1.f - 0.7f) * float (valX) + 0.7f; // whole hue range // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) - Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); + Color::hsv2rgb01 (float (valY), float (valX), value, R, G, B); } - caller->ccRed = double(R); - caller->ccGreen = double(G); - caller->ccBlue = double(B); + caller->ccRed = double (R); + caller->ccGreen = double (G); + caller->ccBlue = double (B); } void ColorAppearance::adjusterChanged (Adjuster* a, double newval) { if (listener && (multiImage || getEnabled()) ) { - if(a == degree) { + if (a == degree) { listener->panelChanged (EvCATDegree, a->getTextValue()); - } else if(a == adapscen) { + } else if (a == adapscen) { listener->panelChanged (EvCATAdapscen, a->getTextValue()); - } else if(a == adaplum) { + } else if (a == adaplum) { listener->panelChanged (EvCATAdapLum, a->getTextValue()); - } else if(a == badpixsl) { + } else if (a == badpixsl) { listener->panelChanged (EvCATbadpix, a->getTextValue()); - } else if(a == jlight) { + } else if (a == jlight) { listener->panelChanged (EvCATJLight, a->getTextValue()); - } else if(a == qbright) { + } else if (a == qbright) { listener->panelChanged (EvCATQbright, a->getTextValue()); - } else if(a == chroma) { + } else if (a == chroma) { listener->panelChanged (EvCATChroma, a->getTextValue()); - } else if(a == schroma) { + } else if (a == schroma) { listener->panelChanged (EvCATSChroma, a->getTextValue()); - } else if(a == mchroma) { + } else if (a == mchroma) { listener->panelChanged (EvCATMChroma, a->getTextValue()); - } else if(a == rstprotection) { + } else if (a == rstprotection) { listener->panelChanged (EvCATRstpro, a->getTextValue()); - } else if(a == contrast) { + } else if (a == contrast) { listener->panelChanged (EvCATContrast, a->getTextValue()); - } else if(a == colorh) { + } else if (a == colorh) { listener->panelChanged (EvCAThue, a->getTextValue()); - } else if(a == qcontrast) { + } else if (a == qcontrast) { listener->panelChanged (EvCATQContrast, a->getTextValue()); } @@ -1114,19 +1114,19 @@ void ColorAppearance::adjusterAutoToggled (Adjuster* a, bool newval) if (multiImage) { if (degree->getAutoInconsistent()) { - degree->setAutoInconsistent(false); - degree->setAutoValue(false); + degree->setAutoInconsistent (false); + degree->setAutoValue (false); } else if (lastAutoDegree) { - degree->setAutoInconsistent(true); + degree->setAutoInconsistent (true); } lastAutoDegree = degree->getAutoValue(); if (adapscen->getAutoInconsistent()) { - adapscen->setAutoInconsistent(false); - adapscen->setAutoValue(false); + adapscen->setAutoInconsistent (false); + adapscen->setAutoValue (false); } else if (lastAutoAdapscen) { - adapscen->setAutoInconsistent(true); + adapscen->setAutoInconsistent (true); } lastAutoAdapscen = adapscen->getAutoValue(); @@ -1135,23 +1135,23 @@ void ColorAppearance::adjusterAutoToggled (Adjuster* a, bool newval) if (listener && (multiImage || getEnabled()) ) { - if(a == degree) { + if (a == degree) { if (degree->getAutoInconsistent()) { - listener->panelChanged (EvCATAutoDegree, M("GENERAL_UNCHANGED")); + listener->panelChanged (EvCATAutoDegree, M ("GENERAL_UNCHANGED")); } else if (degree->getAutoValue()) { - listener->panelChanged (EvCATAutoDegree, M("GENERAL_ENABLED")); + listener->panelChanged (EvCATAutoDegree, M ("GENERAL_ENABLED")); } else { - listener->panelChanged (EvCATAutoDegree, M("GENERAL_DISABLED")); + listener->panelChanged (EvCATAutoDegree, M ("GENERAL_DISABLED")); } } - if(a == adapscen) { + if (a == adapscen) { if (adapscen->getAutoInconsistent()) { - listener->panelChanged (EvCATAutoAdap, M("GENERAL_UNCHANGED")); + listener->panelChanged (EvCATAutoAdap, M ("GENERAL_UNCHANGED")); } else if (adapscen->getAutoValue()) { - listener->panelChanged (EvCATAutoAdap, M("GENERAL_ENABLED")); + listener->panelChanged (EvCATAutoAdap, M ("GENERAL_ENABLED")); } else { - listener->panelChanged (EvCATAutoAdap, M("GENERAL_DISABLED")); + listener->panelChanged (EvCATAutoAdap, M ("GENERAL_DISABLED")); } } @@ -1163,13 +1163,13 @@ void ColorAppearance::enabledChanged () if (listener) { if (get_inconsistent()) { - listener->panelChanged (EvCATEnabled, M("GENERAL_UNCHANGED")); + listener->panelChanged (EvCATEnabled, M ("GENERAL_UNCHANGED")); } else if (getEnabled()) { - listener->panelChanged (EvCATEnabled, M("GENERAL_ENABLED")); + listener->panelChanged (EvCATEnabled, M ("GENERAL_ENABLED")); curveEditorG->set_sensitive (true); toneCurveMode->set_sensitive (true); } else { - listener->panelChanged (EvCATEnabled, M("GENERAL_DISABLED")); + listener->panelChanged (EvCATEnabled, M ("GENERAL_DISABLED")); } } } @@ -1282,12 +1282,12 @@ void ColorAppearance::setBatchMode (bool batchMode) qcontrast->showEditedCB (); colorh->showEditedCB (); - surround->append (M("GENERAL_UNCHANGED")); - wbmodel->append (M("GENERAL_UNCHANGED")); - algo->append (M("GENERAL_UNCHANGED")); - toneCurveMode->append (M("GENERAL_UNCHANGED")); - toneCurveMode2->append (M("GENERAL_UNCHANGED")); - toneCurveMode3->append (M("GENERAL_UNCHANGED")); + surround->append (M ("GENERAL_UNCHANGED")); + wbmodel->append (M ("GENERAL_UNCHANGED")); + algo->append (M ("GENERAL_UNCHANGED")); + toneCurveMode->append (M ("GENERAL_UNCHANGED")); + toneCurveMode2->append (M ("GENERAL_UNCHANGED")); + toneCurveMode3->append (M ("GENERAL_UNCHANGED")); curveEditorG->setBatchMode (batchMode); curveEditorG2->setBatchMode (batchMode); @@ -1306,35 +1306,35 @@ void ColorAppearance::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu void ColorAppearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd) { - degree->setAddMode(degreeadd); - adapscen->setAddMode(adapscenadd); - adaplum->setAddMode(adaplumadd); - badpixsl->setAddMode(badpixsladd); - jlight->setAddMode(jlightadd); - qbright->setAddMode(qbrightadd); - chroma->setAddMode(chromaadd); - schroma->setAddMode(schromaadd); - mchroma->setAddMode(mchromaadd); - rstprotection->setAddMode(rstprotectionadd); - contrast->setAddMode(contrastadd); - qcontrast->setAddMode(qcontrastadd); - colorh->setAddMode(colorhadd); + degree->setAddMode (degreeadd); + adapscen->setAddMode (adapscenadd); + adaplum->setAddMode (adaplumadd); + badpixsl->setAddMode (badpixsladd); + jlight->setAddMode (jlightadd); + qbright->setAddMode (qbrightadd); + chroma->setAddMode (chromaadd); + schroma->setAddMode (schromaadd); + mchroma->setAddMode (mchromaadd); + rstprotection->setAddMode (rstprotectionadd); + contrast->setAddMode (contrastadd); + qcontrast->setAddMode (qcontrastadd); + colorh->setAddMode (colorhadd); } void ColorAppearance::trimValues (rtengine::procparams::ProcParams* pp) { - degree->trimValue(pp->colorappearance.degree); - adapscen->trimValue(pp->colorappearance.adapscen); - adaplum->trimValue(pp->colorappearance.adaplum); - badpixsl->trimValue(pp->colorappearance.badpixsl); - jlight->trimValue(pp->colorappearance.jlight); - qbright->trimValue(pp->colorappearance.qbright); - chroma->trimValue(pp->colorappearance.chroma); - schroma->trimValue(pp->colorappearance.schroma); - mchroma->trimValue(pp->colorappearance.mchroma); - rstprotection->trimValue(pp->colorappearance.rstprotection); - contrast->trimValue(pp->colorappearance.contrast); - qcontrast->trimValue(pp->colorappearance.qcontrast); - colorh->trimValue(pp->colorappearance.colorh); + degree->trimValue (pp->colorappearance.degree); + adapscen->trimValue (pp->colorappearance.adapscen); + adaplum->trimValue (pp->colorappearance.adaplum); + badpixsl->trimValue (pp->colorappearance.badpixsl); + jlight->trimValue (pp->colorappearance.jlight); + qbright->trimValue (pp->colorappearance.qbright); + chroma->trimValue (pp->colorappearance.chroma); + schroma->trimValue (pp->colorappearance.schroma); + mchroma->trimValue (pp->colorappearance.mchroma); + rstprotection->trimValue (pp->colorappearance.rstprotection); + contrast->trimValue (pp->colorappearance.contrast); + qcontrast->trimValue (pp->colorappearance.qcontrast); + colorh->trimValue (pp->colorappearance.colorh); } From 95f3eaf001188a1e098bea246e6736751e5fcd0d Mon Sep 17 00:00:00 2001 From: Morgan Hardwood <bugs@londonlight.org> Date: Wed, 31 May 2017 18:55:41 +0200 Subject: [PATCH 29/32] Diagonal curve should be bypassed when it is linear, regardless of node count, fixes #3902 --- rtengine/diagonalcurves.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index 1c75e3059..82faa6cd5 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -58,7 +58,7 @@ DiagonalCurve::DiagonalCurve (const std::vector<double>& p, int poly_pn) x[i] = p[ix++]; y[i] = p[ix++]; - if (x[i] != y[i]) { + if (std::fabs(x[i] - y[i]) >= 0.000009) { identity = false; } } From 40ee59147488c228baf446f7573e25bbced991d7 Mon Sep 17 00:00:00 2001 From: heckflosse <heckflosse67@gmx.de> Date: Wed, 31 May 2017 19:24:33 +0200 Subject: [PATCH 30/32] Added a comment for last commit --- rtengine/diagonalcurves.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index 82faa6cd5..3f885782c 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -59,6 +59,8 @@ DiagonalCurve::DiagonalCurve (const std::vector<double>& p, int poly_pn) y[i] = p[ix++]; if (std::fabs(x[i] - y[i]) >= 0.000009) { + // the smallest possible difference between x and y curve point values is ~ 0.00001 + // checking against >= 0.000009 is a bit saver than checking against >= 0.00001 identity = false; } } From 44e1ba3aad54ea336e1651c8c9c95d80540be179 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood <bugs@londonlight.org> Date: Fri, 2 Jun 2017 10:38:53 +0200 Subject: [PATCH 31/32] Display release notes only if new major version, #3905 --- rtgui/rtwindow.cc | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index ccf0b26e2..ca1a011b9 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -18,6 +18,7 @@ */ #include <gtkmm.h> +#include <regex> #include "rtwindow.h" #include "options.h" #include "preferences.h" @@ -319,22 +320,38 @@ void RTWindow::on_realize () mainWindowCursorManager.init(get_window()); - // Check if first run of this version, then display the Release Notes text - if (options.version != versionString) { + // Display release notes only if new major version. + // Pattern matches "5.1" from "5.1-23-g12345678" + std::string vs[] = {versionString, options.version}; + std::regex pat("(^[0-9.]+).*"); + std::smatch sm; + std::vector<std::string> vMajor; + for (const auto &v : vs) { + if (std::regex_match(v, sm, pat)) { + if (sm.size() == 2) { + std::ssub_match smsub = sm[1]; + vMajor.push_back(smsub.str()); + } + } + } - // Update the version parameter with the right value - options.version = versionString; + if (vMajor.size() == 2) { + if (vMajor[0] != vMajor[1]) { - splash = new Splash (*this); - splash->set_transient_for (*this); - splash->signal_delete_event().connect( sigc::mem_fun(*this, &RTWindow::splashClosed) ); + // Update the version parameter with the right value + options.version = versionString; - if (splash->hasReleaseNotes()) { - splash->showReleaseNotes(); - splash->show (); - } else { - delete splash; - splash = nullptr; + splash = new Splash (*this); + splash->set_transient_for (*this); + splash->signal_delete_event().connect( sigc::mem_fun(*this, &RTWindow::splashClosed) ); + + if (splash->hasReleaseNotes()) { + splash->showReleaseNotes(); + splash->show (); + } else { + delete splash; + splash = nullptr; + } } } } From 0a18c96ae4e91c201ab337b6b27268e9ae8d6154 Mon Sep 17 00:00:00 2001 From: Desmis <jdesmis@gmail.com> Date: Sat, 3 Jun 2017 08:43:11 +0200 Subject: [PATCH 32/32] Increase slightly range color histogram Ciecam mode --- rtengine/improcfun.cc | 4 ++-- rtgui/diagonalcurveeditorsubgroup.cc | 4 +++- rtgui/labcurve.cc | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 96920c3da..5c96aa6fd 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -2365,13 +2365,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int hist16JCAM[posl]++; if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { - chsacol = 327.f; + chsacol = 400.f;//327 colch = C; //450.0 approximative factor for s 320 for M } else if (curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0f; colch = s; } else { /*if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF)*/ - chsacol = 327.0f; + chsacol = 400.0f;//327 colch = M; } diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index d12cdf023..936bf0d64 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -620,7 +620,9 @@ void DiagonalCurveEditorSubGroup::switchGUI() } else { // dCurve ave a ColorProvider or a background gradient defined, so we create/update the object if (!leftBar) { - leftBar = new ColoredBar(RTO_Bottom2Top); + leftBar = new ColoredBar(RTO_Bottom2Top); + + } if (barColorProvider) { diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index dc9e404fb..c39dc99fc 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -574,6 +574,21 @@ void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType // whole hue range // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); + } else if (callerId == 6) { // cc - left bar + + float value = (1.f - 0.7f) * float(valX) + 0.7f; + float hue = (1.14056f - 0.92f) * float(valY) + 0.92f; + + if (hue > 1.0f) { + hue -= 1.0f; + } + + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) + Color::hsv2rgb01(hue, float(valX), value, R, G, B); + + // whole hue range + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) + // Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); } else if (callerId == 3) { // lc - bottom bar float value = (1.f - 0.7f) * float(valX) + 0.7f;