rawTherapee/rtengine/simpleprocess.cc

1191 lines
47 KiB
C++

/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rtengine.h"
#include "colortemp.h"
#include "imagesource.h"
#include "improcfun.h"
#include "curves.h"
#include "iccstore.h"
#include "clutstore.h"
#include "processingjob.h"
#include <glibmm.h>
#include "../rtgui/options.h"
#include "rawimagesource.h"
#include "../rtgui/multilangmgr.h"
#include "mytime.h"
#undef THREAD_PRIORITY_NORMAL
namespace rtengine {
extern const Settings* settings;
IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool tunnelMetaData, bool flush) {
errorCode = 0;
ProcessingJobImpl* job = static_cast<ProcessingJobImpl*>(pjob);
if (pl) {
pl->setProgressStr ("PROGRESSBAR_PROCESSING");
pl->setProgress (0.0);
}
InitialImage* ii = job->initialImage;
if (!ii) {
ii = InitialImage::load (job->fname, job->isRaw, &errorCode);
if (errorCode) {
delete job;
return NULL;
}
}
procparams::ProcParams& params = job->pparams;
// acquire image from imagesource
ImageSource* imgsrc = ii->getImageSource ();
int tr = getCoarseBitMask(params.coarse);
int fw, fh;
imgsrc->getFullSize (fw, fh, tr);
// check the crop params
if (params.crop.x > fw || params.crop.y > fh) {
// the crop is completely out of the image, so we disable the crop
params.crop.enabled = false;
// and we set the values to the defaults
params.crop.x = 0;
params.crop.y = 0;
params.crop.w = fw;
params.crop.h = fh;
}
else {
if ((params.crop.x + params.crop.w) > fw) {
// crop overflow in the width dimension ; we trim it
params.crop.w = fw-params.crop.x;
}
if ((params.crop.y + params.crop.h) > fh) {
// crop overflow in the height dimension ; we trim it
params.crop.h = fh-params.crop.y;
}
}
// MyTime t1,t2;
// t1.set();
ImProcFunctions ipf (&params, true);
PreviewProps pp (0, 0, fw, fh, 1);
imgsrc->preprocess( params.raw, params.lensProf, params.coarse);
if (params.toneCurve.autoexp) {// this enabled HLRecovery
LUTu histRedRaw(256), histGreenRaw(256), histBlueRaw(256);
imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw);
if (ToneCurveParams::HLReconstructionNecessary(histRedRaw, histGreenRaw, histBlueRaw) && !params.toneCurve.hrenabled) {
params.toneCurve.hrenabled=true;
// WARNING: Highlight Reconstruction is being forced 'on', should we force a method here too?
}
}
if (pl) pl->setProgress (0.20);
imgsrc->demosaic( params.raw);
if (pl) pl->setProgress (0.30);
imgsrc->HLRecovery_Global( params.toneCurve );
if (pl) pl->setProgress (0.40);
// set the color temperature
ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method);
if (params.wb.method=="Camera")
currWB = imgsrc->getWB ();
else if (params.wb.method=="Auto") {
double rm, gm, bm;
imgsrc->getAutoWBMultipliers(rm, gm, bm);
currWB.update(rm, gm, bm, params.wb.equal);
}
NoiseCurve noiseLCurve;
NoiseCurve noiseCCurve;
Imagefloat *calclum = NULL ;
params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve);
float autoNR = (float) settings->nrauto;//
float autoNRmax = (float) settings->nrautomax;//
int tilesize;
int overlap;
if(settings->leveldnti ==0) {
tilesize = 1024;
overlap = 128;
}
if(settings->leveldnti ==1) {
tilesize = 768;
overlap = 96;
}
// const int tilesize = 768;
// const int overlap = 96;
int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip;
ipf.Tile_calc (tilesize, overlap, 2, fw, fh, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip);
int nbtl=numtiles_W*numtiles_H;
if((settings->leveldnautsimpl==1 && params.dirpyrDenoise.Cmethod=="AUT") || (settings->leveldnautsimpl==0 && params.dirpyrDenoise.C2method=="AUTO")) nbtl=9;
float *ch_M = new float [nbtl];//allocate memory
float *max_r = new float [nbtl];
float *max_b = new float [nbtl];
float *min_b = new float [9];
float *min_r = new float [9];
float *lumL = new float [nbtl];
float *chromC = new float [nbtl];
float *ry = new float [nbtl];
float *sk = new float [nbtl];
float *pcsk = new float [nbtl];
float *Max_R_ =new float [nbtl];
float *Max_B_ = new float [nbtl];
// printf("expert=%d\n",settings->leveldnautsimpl);
if(settings->leveldnautsimpl==1 && params.dirpyrDenoise.Cmethod=="PON") {
MyTime t1pone,t2pone;
t1pone.set();
int crW,crH;
if(settings->leveldnv ==0) {crW=100;crH=100;}
if(settings->leveldnv ==1) {crW=250;crH=250;}
if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(tileHskip/2);}
// if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(1.15f*(tileWskip/2));}//adapted to scale of preview
if(settings->leveldnv ==3) {crW=tileWskip-10;crH=tileHskip-10;}
float lowdenoise=1.f;
int levaut=settings->leveldnaut;
if(levaut==1) //Standard
lowdenoise=0.7f;
// int crW=tileWskip-10;//crop noise width
// int crH=tileHskip-10;//crop noise height
// Imagefloat *origCropPart;//init auto noise
// origCropPart = new Imagefloat (crW, crH);//allocate memory
if (params.dirpyrDenoise.enabled) {//evaluate Noise
LUTf gamcurve(65536,0);
float gam, gamthresh, gamslope;
ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope);
#pragma omp parallel
{
Imagefloat *origCropPart;//init auto noise
origCropPart = new Imagefloat (crW, crH);//allocate memory
Imagefloat *provicalc = new Imagefloat ((crW+1)/2, (crH+1)/2);//for denoise curves
int skipP=1;
#pragma omp for schedule(dynamic) collapse(2) nowait
for(int wcr=0;wcr<numtiles_W;wcr++) {
for(int hcr=0;hcr<numtiles_H;hcr++) {
int beg_tileW=wcr*tileWskip + tileWskip/2.f - crW/2.f;
int beg_tileH=hcr*tileHskip + tileHskip/2.f - crH/2.f;
PreviewProps ppP (beg_tileW , beg_tileH, crW, crH, skipP);
imgsrc->getImage (currWB, tr, origCropPart, ppP, params.toneCurve, params.icm, params.raw );
// we only need image reduced to 1/4 here
for(int ii=0;ii<crH;ii+=2){
for(int jj=0;jj<crW;jj+=2){
provicalc->r(ii>>1,jj>>1) = origCropPart->r(ii,jj);
provicalc->g(ii>>1,jj>>1) = origCropPart->g(ii,jj);
provicalc->b(ii>>1,jj>>1) = origCropPart->b(ii,jj);
}
}
imgsrc->convertColorSpace(provicalc, params.icm, currWB);//for denoise luminance curve
float maxr=0.f;
float maxb=0.f;
float pondcorrec=1.0f;
float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc;
int Nb;
chaut=0.f;redaut=0.f; blueaut=0.f; maxredaut=0.f; maxblueaut=0.f;chromina=0.f; sigma=0.f;
ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
float multip=1.f;
float adjustr=1.f;
if (params.icm.working=="ProPhoto") {adjustr =1.f;}//
else if (params.icm.working=="Adobe RGB") {adjustr = 1.f/1.3f;}
else if (params.icm.working=="sRGB") {adjustr = 1.f/1.3f;}
else if (params.icm.working=="WideGamut") {adjustr =1.f/1.1f;}
else if (params.icm.working=="Beta RGB") {adjustr =1.f/1.2f;}
else if (params.icm.working=="BestRGB") {adjustr =1.f/1.2f;}
else if (params.icm.working=="BruceRGB") {adjustr =1.f/1.2f;}
if(!imgsrc->isRAW()) multip=2.f;//take into account gamma for TIF / JPG approximate value...not good fot gamma=1
float maxmax=max(maxredaut,maxblueaut);
float delta;
int mode=2;
int lissage=settings->leveldnliss;
ipf.calcautodn_info (chaut, delta, Nb, levaut, maxmax, lumema, chromina, mode, lissage, redyel, skinc, nsknc);
// printf("PROCESS cha=%f red=%f bl=%f redM=%f bluM=%f chrom=%f sigm=%f lum=%f sigL=%f\n",chaut,redaut,blueaut, maxredaut, maxblueaut, chromina, sigma, lumema, sigma_L);
if(maxredaut > maxblueaut) {
maxr=(delta)/((autoNRmax*multip*adjustr*lowdenoise)/2.f);
if(minblueaut <= minredaut && minblueaut < chaut) maxb=(-chaut+minblueaut)/(autoNRmax*multip*adjustr*lowdenoise);
}
else {
maxb=(delta)/((autoNRmax*multip*adjustr*lowdenoise)/2.f);
if(minredaut <= minblueaut && minredaut < chaut) maxr=(-chaut+minredaut)/(autoNRmax*multip*adjustr*lowdenoise);
}//maxb mxr - empirical evaluation red / blue
ch_M[hcr*numtiles_W + wcr]=pondcorrec*chaut/(autoNR*multip*adjustr*lowdenoise);
max_r[hcr*numtiles_W + wcr]=pondcorrec*maxr;
max_b[hcr*numtiles_W + wcr]=pondcorrec*maxb;
lumL[hcr*numtiles_W + wcr]=lumema;
chromC[hcr*numtiles_W + wcr]=chromina;
ry[hcr*numtiles_W + wcr]=redyel;
sk[hcr*numtiles_W + wcr]=skinc;
pcsk[hcr*numtiles_W + wcr]=nsknc;
}
}
delete provicalc;
delete origCropPart;
}
int liss=settings->leveldnliss;//smooth result around mean
if(liss==2 || liss==3){
// I smooth only mean and not delta (max)
float nchm=0.f;
float koef=0.4f;//between 0.1 to 0.9
if(liss==3) koef=0.0f;//quasi auto for mean Ch
for(int wcr=0;wcr<numtiles_W;wcr++) {
for(int hcr=0;hcr<numtiles_H;hcr++) {
nchm+=ch_M[hcr*numtiles_W + wcr];
}
}
nchm/=(numtiles_H*numtiles_W);
for(int wcr=0;wcr<numtiles_W;wcr++) {
for(int hcr=0;hcr<numtiles_H;hcr++) {
ch_M[hcr*numtiles_W + wcr]=nchm+(ch_M[hcr*numtiles_W + wcr]-nchm)*koef;
}
}
}
if(liss==3){//same as auto but with much cells
float MaxR=0.f;
float MaxB=0.f;
float MaxRMoy=0.f;
float MaxBMoy=0.f;
for(int k=0;k<nbtl;k++) {
MaxBMoy+=max_b[k];
MaxRMoy+=max_r[k];
if(max_r[k]>MaxR) MaxR=Max_R_[k];
if(max_b[k]>MaxB) MaxB=Max_B_[k];
}
MaxBMoy/=nbtl;
MaxRMoy/=nbtl;
for(int k=0;k<nbtl;k++) {
if(MaxR > MaxB) {
max_r[k]=MaxRMoy + (MaxR-MaxRMoy)*0.66f;//#std Dev
//max_b[k]=MinB;
max_b[k]=MaxBMoy + (MaxB-MaxBMoy)*0.66f;
}
else {
max_b[k]=MaxBMoy + (MaxB-MaxBMoy)*0.66f;
//max_r[k]=MinR;
max_r[k]=MaxRMoy + (MaxR-MaxRMoy)*0.66f;
}
}
}
if (settings->verbose) {
t2pone.set();
printf("Info denoise ponderated performed in %d usec:\n", t2pone.etime(t1pone));
}
}
}
if((settings->leveldnautsimpl==1 && params.dirpyrDenoise.Cmethod=="AUT") || (settings->leveldnautsimpl==0 && params.dirpyrDenoise.C2method=="AUTO")) {
MyTime t1aue,t2aue;
t1aue.set();
int crW,crH;
if(settings->leveldnv ==0) {crW=100;crH=100;}
if(settings->leveldnv ==1) {crW=250;crH=250;}
if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(tileHskip/2);}
// if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(1.15f*(tileWskip/2));}//adapted to scale of preview
if(settings->leveldnv ==3) {crW=tileWskip-10;crH=tileHskip-10;}
float lowdenoise=1.f;
int levaut=settings->leveldnaut;
if(levaut==1) //Standard
lowdenoise=0.7f;
if (params.dirpyrDenoise.enabled) {//evaluate Noise
LUTf gamcurve(65536,0);
float gam, gamthresh, gamslope;
ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope);
int Nb[9];
int coordW[3];//coordonate of part of image to mesure noise
int coordH[3];
int begW=50;
int begH=50;
coordW[0]=begW;coordW[1]=fw/2-crW/2;coordW[2]=fw-crW-begW;
coordH[0]=begH;coordH[1]=fh/2-crH/2;coordH[2]=fh-crH-begH;
#pragma omp parallel
{
Imagefloat *origCropPart;//init auto noise
origCropPart = new Imagefloat (crW, crH);//allocate memory
Imagefloat *provicalc = new Imagefloat ((crW+1)/2, (crH+1)/2);//for denoise curves
#pragma omp for schedule(dynamic) collapse(2) nowait
for(int wcr=0;wcr<=2;wcr++) {
for(int hcr=0;hcr<=2;hcr++) {
PreviewProps ppP (coordW[wcr] , coordH[hcr], crW, crH, 1);
imgsrc->getImage (currWB, tr, origCropPart, ppP, params.toneCurve, params.icm, params.raw);
// we only need image reduced to 1/4 here
for(int ii=0;ii<crH;ii+=2){
for(int jj=0;jj<crW;jj+=2){
provicalc->r(ii>>1,jj>>1) = origCropPart->r(ii,jj);
provicalc->g(ii>>1,jj>>1) = origCropPart->g(ii,jj);
provicalc->b(ii>>1,jj>>1) = origCropPart->b(ii,jj);
}
}
imgsrc->convertColorSpace(provicalc, params.icm, currWB);//for denoise luminance curve
int nb = 0;
float chaut=0.f, redaut=0.f, blueaut=0.f, maxredaut=0.f, maxblueaut=0.f, minredaut=0.f, minblueaut=0.f, nresi=0.f, highresi=0.f, chromina=0.f, sigma=0.f, lumema=0.f, sigma_L=0.f, redyel=0.f, skinc=0.f, nsknc=0.f;
ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
Nb[hcr*3 + wcr] = nb;
ch_M[hcr*3 + wcr] = chaut;
max_r[hcr*3 + wcr] = maxredaut;
max_b[hcr*3 + wcr] = maxblueaut;
min_r[hcr*3 + wcr] = minredaut;
min_b[hcr*3 + wcr] = minblueaut;
lumL[hcr*3 + wcr] = lumema;
chromC[hcr*3 + wcr] = chromina;
ry[hcr*3 + wcr] = redyel;
sk[hcr*3 + wcr] = skinc;
pcsk[hcr*3 + wcr] = nsknc;
}
}
delete provicalc;
delete origCropPart;
}
float chM=0.f;
float MaxR=0.f;
float MaxB=0.f;
float MinR=100000000.f;
float MinB=100000000.f;
float maxr=0.f;
float maxb=0.f;
float multip=1.f;
float adjustr=1.f;
float Max_R[9]={0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f};
float Max_B[9]={0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f};
float Min_R[9];
float Min_B[9];
float MaxRMoy=0.f;
float MaxBMoy=0.f;
float MinRMoy=0.f;
float MinBMoy=0.f;
if (params.icm.working=="ProPhoto") {adjustr =1.f;}
else if (params.icm.working=="Adobe RGB") {adjustr = 1.f/1.3f;}
else if (params.icm.working=="sRGB") {adjustr = 1.f/1.3f;}
else if (params.icm.working=="WideGamut") {adjustr =1.f/1.1f;}
else if (params.icm.working=="Beta RGB") {adjustr =1.f/1.2f;}
else if (params.icm.working=="BestRGB") {adjustr =1.f/1.2f;}
else if (params.icm.working=="BruceRGB") {adjustr =1.f/1.2f;}
if(!imgsrc->isRAW()) multip=2.f;//take into account gamma for TIF / JPG approximate value...not good fot gamma=1
float delta[9];
int mode=1;
int lissage=settings->leveldnliss;
for(int k=0;k<9;k++) {
float maxmax = max(max_r[k],max_b[k]);
ipf.calcautodn_info (ch_M[k], delta[k], Nb[k], levaut, maxmax, lumL[k], chromC[k], mode, lissage, ry[k], sk[k], pcsk[k] );
// printf("ch_M=%f delta=%f\n",ch_M[k], delta[k]);
}
for(int k=0;k<9;k++) {
if(max_r[k] > max_b[k]) {
//printf("R delta=%f koef=%f\n",delta[k],autoNRmax*multip*adjustr*lowdenoise);
Max_R[k]=(delta[k])/((autoNRmax*multip*adjustr*lowdenoise)/2.f);
Min_B[k]= -(ch_M[k]-min_b[k])/(autoNRmax*multip*adjustr*lowdenoise);
Max_B[k]=0.f;
Min_R[k]=0.f;
}
else {
//printf("B delta=%f koef=%f\n",delta[k],autoNRmax*multip*adjustr*lowdenoise);
Max_B[k]=(delta[k])/((autoNRmax*multip*adjustr*lowdenoise)/2.f);
Min_R[k]=- (ch_M[k]-min_r[k]) / (autoNRmax*multip*adjustr*lowdenoise);
Min_B[k]=0.f;
Max_R[k]=0.f;
}
}
for(int k=0;k<9;k++) {
// printf("ch_M= %f Max_R=%f Max_B=%f min_r=%f min_b=%f\n",ch_M[k],Max_R[k], Max_B[k],Min_R[k], Min_B[k]);
chM+=ch_M[k];
MaxBMoy+=Max_B[k];
MaxRMoy+=Max_R[k];
MinRMoy+=Min_R[k];
MinBMoy+=Min_B[k];
if(Max_R[k]>MaxR) MaxR=Max_R[k];
if(Max_B[k]>MaxB) MaxB=Max_B[k];
if(Min_R[k]<MinR) MinR=Min_R[k];
if(Min_B[k]<MinB) MinB=Min_B[k];
}
chM/=9;
MaxBMoy/=9;
MaxRMoy/=9;
MinBMoy/=9;
MinRMoy/=9;
if(MaxR > MaxB) {
maxr=MaxRMoy + (MaxR-MaxRMoy)*0.66f;//#std Dev
// maxb=MinB;
maxb=MinBMoy + (MinB-MinBMoy)*0.66f;
}
else {
maxb=MaxBMoy + (MaxB-MaxBMoy)*0.66f;
// maxr=MinR;
maxr=MinRMoy + (MinR-MinRMoy)*0.66f;
}
// printf("SIMPL cha=%f red=%f bl=%f \n",chM,maxr,maxb);
params.dirpyrDenoise.chroma=chM/(autoNR*multip*adjustr);
params.dirpyrDenoise.redchro=maxr;
params.dirpyrDenoise.bluechro=maxb;
}
if (settings->verbose) {
t2aue.set();
printf("Info denoise auto performed in %d usec:\n", t2aue.etime(t1aue));
}
//end evaluate noise
}
Imagefloat* baseImg = new Imagefloat (fw, fh);
imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw);
if (pl) pl->setProgress (0.45);
// LUTf Noisecurve (65536,0);
//!!!// auto exposure!!!
double expcomp = params.toneCurve.expcomp;
int bright = params.toneCurve.brightness;
int contr = params.toneCurve.contrast;
int black = params.toneCurve.black;
int hlcompr = params.toneCurve.hlcompr;
int hlcomprthresh = params.toneCurve.hlcomprthresh;
if (params.toneCurve.autoexp) {
LUTu aehist; int aehistcompr;
imgsrc->getAutoExpHistogram (aehist, aehistcompr);
ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, expcomp, bright, contr, black, hlcompr,hlcomprthresh);
}
// at this stage, we can flush the raw data to free up quite an important amount of memory
// commented out because it makes the application crash when batch processing...
// TODO: find a better place to flush rawData and rawRGB
if(flush) {
imgsrc->flushRawData();
imgsrc->flushRGB();
}
// perform luma/chroma denoise
// CieImage *cieView;
// NoisCurve noiseLCurve;
// bool lldenoiseutili=false;
// Imagefloat *calclum ;
// params.dirpyrDenoise.getCurves(noiseLCurve, lldenoiseutili);
// if (params.dirpyrDenoise.enabled && lldenoiseutili) {
DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; // make a copy because we cheat here
if(denoiseParams.Lmethod == "CUR") {
if(noiseLCurve)
denoiseParams.luma = 0.5f;
else
denoiseParams.luma = 0.0f;
} else if(denoiseParams.Lmethod=="SLI")
noiseLCurve.Reset();
if (denoiseParams.enabled && (noiseLCurve || noiseCCurve )) {
// we only need image reduced to 1/4 here
calclum = new Imagefloat ((fw+1)/2, (fh+1)/2);//for luminance denoise curve
#pragma omp parallel for
for(int ii=0;ii<fh;ii+=2){
for(int jj=0;jj<fw;jj+=2){
calclum->r(ii>>1,jj>>1) = baseImg->r(ii,jj);
calclum->g(ii>>1,jj>>1) = baseImg->g(ii,jj);
calclum->b(ii>>1,jj>>1) = baseImg->b(ii,jj);
}
}
imgsrc->convertColorSpace(calclum, params.icm, currWB);
}
if (denoiseParams.enabled) {
// CurveFactory::denoiseLL(lldenoiseutili, denoiseParams.lcurve, Noisecurve,1);
//denoiseParams.getCurves(noiseLCurve);
// ipf.RGB_denoise(baseImg, baseImg, calclum, imgsrc->isRAW(), denoiseParams, params.defringe, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, lldenoiseutili);
float chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi;
int kall=2;
ipf.RGB_denoise(kall, baseImg, baseImg, calclum, ch_M, max_r, max_b, imgsrc->isRAW(), denoiseParams, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi);
}
// delete calclum;
delete [] ch_M;
delete [] max_r;
delete [] max_b;
delete [] min_r;
delete [] min_b;
delete [] lumL;
delete [] chromC;
delete [] ry;
delete [] sk;
delete [] pcsk;
delete [] Max_R_;
delete [] Max_B_;
imgsrc->convertColorSpace(baseImg, params.icm, currWB);
// perform first analysis
LUTu hist16 (65536);
LUTu hist16C (65536);
ipf.firstAnalysis (baseImg, &params, hist16);
// perform transform (excepted resizing)
if (ipf.needsTransform()) {
Imagefloat* trImg = new Imagefloat (fw, fh);
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(),
imgsrc->getMetaData()->getFocusDist(), imgsrc->getRotateDegree(), true);
delete baseImg;
baseImg = trImg;
}
// update blurmap
SHMap* shmap = NULL;
if (params.sh.enabled) {
shmap = new SHMap (fw, fh, true);
double radius = sqrt (double(fw*fw+fh*fh)) / 2.0;
double shradius = params.sh.radius;
if (!params.sh.hq) shradius *= radius / 1800.0;
shmap->update (baseImg, shradius, ipf.lumimul, params.sh.hq, 1);
}
// RGB processing
LUTf curve1 (65536);
LUTf curve2 (65536);
LUTf curve (65536,0);
LUTf satcurve (65536,0);
LUTf lhskcurve (65536,0);
LUTf lumacurve(65536,0);
LUTf clcurve (65536,0);
LUTf clToningcurve (65536,0);
LUTf cl2Toningcurve (65536,0);
LUTf wavclCurve (65536,0);
LUTf rCurve (65536,0);
LUTf gCurve (65536,0);
LUTf bCurve (65536,0);
LUTu dummy;
ToneCurve customToneCurve1, customToneCurve2;
ColorGradientCurve ctColorCurve;
OpacityCurve ctOpacityCurve;
ColorAppearance customColCurve1, customColCurve2,customColCurve3 ;
ToneCurve customToneCurvebw1;
ToneCurve customToneCurvebw2;
//if(params.blackwhite.enabled) params.toneCurve.hrenabled=false;
ipf.g = imgsrc->getGamma();
ipf.iGamma = true;
CurveFactory::complexCurve (0.0, black/65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, ipf.g, !ipf.iGamma,
params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2,
hist16, dummy, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2 );
CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, 1);
CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, 1);
CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, 1);
TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working);
TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working);
double wp[3][3] = {
{wprof[0][0],wprof[0][1],wprof[0][2]},
{wprof[1][0],wprof[1][1],wprof[1][2]},
{wprof[2][0],wprof[2][1],wprof[2][2]}};
double wip[3][3] = {
{wiprof[0][0],wiprof[0][1],wiprof[0][2]},
{wiprof[1][0],wiprof[1][1],wiprof[1][2]},
{wiprof[2][0],wiprof[2][1],wiprof[2][2]}
};
bool opautili=false;
params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili);
bool clctoningutili=false;
CurveFactory::curveToningCL(clctoningutili, params.colorToning.clcurve, clToningcurve, 1);
bool llctoningutili=false;
CurveFactory::curveToningLL(llctoningutili, params.colorToning.cl2curve, cl2Toningcurve, 1);
LabImage* labView = new LabImage (fw,fh);
CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1);
double rrm, ggm, bbm;
float autor, autog, autob;
float satLimit = float(params.colorToning.satProtectionThreshold)/100.f*0.7f+0.3f;
float satLimitOpacity = 1.f-(float(params.colorToning.saturatedOpacity)/100.f);
if(params.colorToning.enabled && params.colorToning.autosat){//for colortoning evaluation of saturation settings
float moyS=0.f;
float eqty=0.f;
ipf.moyeqt (baseImg, moyS, eqty);//return image : mean saturation and standard dev of saturation
//printf("moy=%f ET=%f\n", moyS,eqty);
float satp=((moyS+1.5f*eqty)-0.3f)/0.7f;//1.5 sigma ==> 93% pixels with high saturation -0.3 / 0.7 convert to Hombre scale
if(satp >= 0.92f) satp=0.92f;//avoid values too high (out of gamut)
if(satp <= 0.15f) satp=0.15f;//avoid too low values
satLimit= 100.f*satp;
satLimitOpacity= 100.f*(moyS-0.85f*eqty);//-0.85 sigma==>20% pixels with low saturation
}
autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000)
DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB);
ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve,customToneCurve1, customToneCurve2,customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf);
if (settings->verbose)
printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob);
// if clut was used and size of clut cache == 1 we free the memory used by the clutstore (default clut cache size = 1 for 32 bit OS)
if ( params.filmSimulation.enabled && !params.filmSimulation.clutFilename.empty() && options.clutCacheSize == 1)
clutStore.clearCache();
// freeing up some memory
customToneCurve1.Reset();
customToneCurve2.Reset();
ctColorCurve.Reset();
ctOpacityCurve.Reset();
noiseLCurve.Reset();
noiseCCurve.Reset();
customToneCurvebw1.Reset();
customToneCurvebw2.Reset();
// Freeing baseImg because not used anymore
delete baseImg;
baseImg = NULL;
if (shmap)
delete shmap;
shmap = NULL;
if (pl)
pl->setProgress (0.5);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// start tile processing...???
hist16.clear(); hist16C.clear();
if(params.labCurve.contrast !=0) {//only use hist16 for contrast
#ifdef _OPENMP
#pragma omp parallel shared(hist16,labView, fh, fw)
#endif
{
LUTu hist16thr (65536); // one temporary lookup table per thread
hist16thr.clear();
#ifdef _OPENMP
#pragma omp for schedule(static) nowait
#endif
for (int i=0; i<fh; i++)
for (int j=0; j<fw; j++){
hist16thr[CLIP((int)((labView->L[i][j])))]++;
}
#pragma omp critical
{
for(int i=0;i<65536;i++)
hist16[i] += hist16thr[i];
}
}
}
bool utili=false;
bool autili=false;
bool butili=false;
bool ccutili=false;
bool cclutili=false;
bool clcutili=false;
CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve,hist16, hist16, lumacurve, dummy, 1, utili);
CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, hist16C, dummy, 1);
CurveFactory::complexsgnCurve (1.f, autili, butili, ccutili, cclutili, params.labCurve.chromaticity, params.labCurve.rstprotection,
params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve,params.labCurve.lccurve,curve1, curve2, satcurve,lhskcurve,
hist16C, hist16C, dummy,dummy,
1);
ipf.chromiLuminanceCurve (NULL, 1,labView, labView, curve1, curve2, satcurve,lhskcurve,clcurve, lumacurve, utili, autili, butili, ccutili,cclutili, clcutili, dummy, dummy, dummy, dummy);
if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled))ipf.EPDToneMap(labView,5,1);
ipf.vibrance(labView);
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) ipf.impulsedenoise (labView);
// for all treatments Defringe, Sharpening, Contrast detail ,Microcontrast they are activated if "CIECAM" function are disabled
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) ipf.defringe (labView);
if (params.sharpenEdge.enabled) {
ipf.MLsharpen(labView);
}
if (params.sharpenMicro.enabled) {
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) ipf.MLmicrocontrast (labView);//!params.colorappearance.sharpcie
}
if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) {
float **buffer = new float*[fh];
for (int i=0; i<fh; i++)
buffer[i] = new float[fw];
ipf.sharpening (labView, (float**)buffer, params.sharpening);
for (int i=0; i<fh; i++)
delete [] buffer[i];
delete [] buffer;
}
WaveletParams WaveParams = params.wavelet;
WavCurve wavCLVCurve;
WavOpacityCurveRG waOpacityCurveRG;
WavOpacityCurveBY waOpacityCurveBY;
WavOpacityCurveW waOpacityCurveW;
WavOpacityCurveWL waOpacityCurveWL;
params.wavelet.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL );
// directional pyramid wavelet
if((params.colorappearance.enabled && !settings->autocielab) || !params.colorappearance.enabled) ipf.dirpyrequalizer (labView, 1);//TODO: this is the luminance tonecurve, not the RGB one
int kall=2;
bool wavcontlutili=false;
CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve,/* hist16C, dummy,*/ 1);
if((params.wavelet.enabled)) ipf.ip_wavelet(labView, labView, kall, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, wavcontlutili, 1);
wavCLVCurve.Reset();
//Colorappearance and tone-mapping associated
int f_w=1,f_h=1;
int begh = 0, endh = fh;
if(params.colorappearance.tonecie || params.colorappearance.enabled){f_w=fw;f_h=fh;}
CieImage *cieView = new CieImage (f_w,(f_h));
begh=0;
endh=fh;
CurveFactory::curveLightBrightColor (
params.colorappearance.curveMode, params.colorappearance.curve,
params.colorappearance.curveMode2, params.colorappearance.curve2,
params.colorappearance.curveMode3, params.colorappearance.curve3,
hist16, hist16,dummy,
hist16C, dummy,
customColCurve1,
customColCurve2,
customColCurve3,
1);
if(params.colorappearance.enabled){
double adap;
float fnum = imgsrc->getMetaData()->getFNumber ();// F number
float fiso = imgsrc->getMetaData()->getISOSpeed () ;// ISO
float fspeed = imgsrc->getMetaData()->getShutterSpeed () ;//speed
float fcomp = imgsrc->getMetaData()->getExpComp ();//compensation + -
if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) {
adap=2000.;
}//if no exif data or wrong
else {
float E_V = fcomp + log2 ((fnum*fnum) / fspeed / (fiso/100.f));
E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV
E_V += log2(params.raw.expos);// exposure raw white point ; log2 ==> linear to EV
adap = powf(2.f, E_V-3.f);//cd / m2
}
LUTf CAMBrightCurveJ;
LUTf CAMBrightCurveQ;
float CAMMean;
if (params.sharpening.enabled) {
float d;
double dd;
int sk=1;
if(settings->ciecamfloat) ipf.ciecam_02float (cieView, float(adap), begh, endh,1,2, labView, &params,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, sk, 1);
else ipf.ciecam_02 (cieView, adap, begh, endh,1,2, labView, &params,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, 1, 1);
}
else {
float d;
double dd;
int sk=1;
if(settings->ciecamfloat) ipf.ciecam_02float (cieView, float(adap), begh, endh,1,2, labView, &params,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, sk, 1);
else ipf.ciecam_02 (cieView, adap, begh, endh,1, 2, labView, &params,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, 1, 1);
}
}
delete cieView;
cieView = NULL;
// end tile processing...???
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (pl) pl->setProgress (0.60);
int imw, imh;
double tmpScale = ipf.resizeScale(&params, fw, fh, imw, imh);
bool labResize = params.resize.enabled && params.resize.method != "Nearest" && tmpScale != 1.0;
LabImage *tmplab;
// crop and convert to rgb16
int cx = 0, cy = 0, cw = labView->W, ch = labView->H;
if (params.crop.enabled) {
cx = params.crop.x;
cy = params.crop.y;
cw = params.crop.w;
ch = params.crop.h;
if(labResize) { // crop lab data
tmplab = new LabImage(cw,ch);
for(int row = 0;row<ch;row++) {
for(int col = 0;col<cw;col++) {
tmplab->L[row][col] = labView->L[row+cy][col+cx];
tmplab->a[row][col] = labView->a[row+cy][col+cx];
tmplab->b[row][col] = labView->b[row+cy][col+cx];
}
}
delete labView;
labView = tmplab;
cx = 0;
cy = 0;
}
}
if (labResize) { // resize lab data
// resize image
tmplab = new LabImage(imw,imh);
ipf.Lanczos (labView, tmplab, tmpScale);
delete labView;
labView = tmplab;
cw = labView->W;
ch = labView->H;
if(params.prsharpening.enabled) {
float **buffer = new float*[ch];
for (int i=0; i<ch; i++)
buffer[i] = new float[cw];
ipf.sharpening (labView, (float**)buffer, params.prsharpening);
for (int i=0; i<ch; i++)
delete [] buffer[i];
delete [] buffer;
}
}
Image16* readyImg = NULL;
cmsHPROFILE jprof = NULL;
bool customGamma = false;
bool useLCMS = false;
if(params.icm.gamma != "default" || params.icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8
cmsMLU *DescriptionMLU, *CopyrightMLU, *DmndMLU, *DmddMLU;// for modification TAG
cmsToneCurve* GammaTRC[3] = { NULL, NULL, NULL };
cmsFloat64Number Parameters[7];
double ga0,ga1,ga2,ga3,ga4,ga5,ga6;
// if(params.blackwhite.enabled) params.toneCurve.hrenabled=false;
readyImg = ipf.lab2rgb16b (labView, cx, cy, cw, ch, params.icm.output, params.icm.working, params.icm.gamma, params.icm.freegamma, params.icm.gampos, params.icm.slpos, ga0,ga1,ga2,ga3,ga4,ga5,ga6, params.blackwhite.enabled );
customGamma = true;
//or selected Free gamma
useLCMS=false;
bool pro=false;
Glib::ustring chpro, outProfile;
bool present_space[9]={false,false,false,false,false,false,false,false,false};
std::vector<Glib::ustring> opnames = iccStore->getOutputProfiles ();
//test if files are in system
for (int j=0; j<9; j++) {
// one can modify "option" [Color Management] to adapt the profile's name if they are different for windows, MacOS, Linux ??
// some of them are actually provided by RT, thanks to Jacques Desmis
if (j==0) chpro=options.rtSettings.prophoto;
else if(j==1) chpro=options.rtSettings.adobe;
else if(j==2) chpro=options.rtSettings.widegamut;
else if(j==3) chpro=options.rtSettings.beta;
else if(j==4) chpro=options.rtSettings.best;
else if(j==5) chpro=options.rtSettings.bruce;
else if(j==6) chpro=options.rtSettings.srgb;
else if(j==7) chpro=options.rtSettings.srgb10;//gamma 1.0
else if(j==8) chpro=options.rtSettings.prophoto10;//gamma 1.0
for (unsigned int i=0; i<opnames.size(); i++) {
if(chpro.compare(opnames[i]) ==0) present_space[j]=true;
}
if (!present_space[j] && settings->verbose) printf("Missing file: %s\n", chpro.c_str());
}
if (params.icm.freegamma && params.icm.gampos < 1.35) pro=true; //select profil with gammaTRC modified :
else if (params.icm.gamma=="linear_g1.0" || (params.icm.gamma=="High_g1.3_s3.35")) pro=true;//pro=0 RT_sRGB || Prophoto
// Check that output profiles exist, otherwise use LCMS2
// Use the icc/icm profiles associated to possible working profiles, set in "options"
if (params.icm.working=="ProPhoto" && present_space[0] && !pro) outProfile=options.rtSettings.prophoto;
else if (params.icm.working=="Adobe RGB" && present_space[1] ) outProfile=options.rtSettings.adobe;
else if (params.icm.working=="WideGamut" && present_space[2] ) outProfile=options.rtSettings.widegamut;
else if (params.icm.working=="Beta RGB" && present_space[3] ) outProfile=options.rtSettings.beta;
else if (params.icm.working=="BestRGB" && present_space[4] ) outProfile=options.rtSettings.best;
else if (params.icm.working=="BruceRGB" && present_space[5] ) outProfile=options.rtSettings.bruce;
else if (params.icm.working=="sRGB" && present_space[6] && !pro) outProfile=options.rtSettings.srgb;
else if (params.icm.working=="sRGB" && present_space[7] && pro) outProfile=options.rtSettings.srgb10;
else if (params.icm.working=="ProPhoto" && present_space[8] && pro) outProfile=options.rtSettings.prophoto10;
else {
// Should not occurs
if (settings->verbose) printf("\"%s\": unknown working profile! - use LCMS2 substitution\n", params.icm.working.c_str() );
useLCMS=true;
}
//begin adaptation rTRC gTRC bTRC
//"jprof" profile has the same characteristics than RGB values, but TRC are adapted... for applying profile
if (!useLCMS) {
if (settings->verbose) printf("Output Gamma - profile: \"%s\"\n", outProfile.c_str() ); //c_str()
jprof = iccStore->getProfile(outProfile); //get output profile
if (jprof == NULL) {
useLCMS = true;
if (settings->verbose) printf("\"%s\" ICC output profile not found!\n", outProfile.c_str());
}
else {
Parameters[0] = ga0;
Parameters[1] = ga1;
Parameters[2] = ga2;
Parameters[3] = ga3;
Parameters[4] = ga4;
Parameters[5] = ga5;
Parameters[6] = ga6;
// 7 parameters for smoother curves
//change desc Tag , to "free gamma", or "BT709", etc.
cmsContext ContextID = cmsGetProfileContextID(jprof);//modification TAG
DescriptionMLU = cmsMLUalloc(ContextID, 1);
CopyrightMLU = cmsMLUalloc(ContextID, 1);//for ICC
DmndMLU=cmsMLUalloc(ContextID, 1);//for ICC
DmddMLU=cmsMLUalloc(ContextID, 1);// for ICC
// instruction with //ICC are used for generate icc profile
if (DescriptionMLU == NULL) printf("Description error\n");
cmsMLUsetWide(CopyrightMLU, "en", "US", L"General Public License - AdobeRGB compatible") ;//adapt to profil
cmsMLUsetWide(DmndMLU, "en", "US", L"RawTherapee") ;
cmsMLUsetWide(DmddMLU, "en", "US", L"RTMedium") ; //adapt to profil
//display Tag desc with : selection of gamma and Primaries
if (!params.icm.freegamma) {
std::wstring gammaStr;
if(params.icm.gamma=="High_g1.3_s3.35") {
gammaStr = std::wstring(L"GammaTRC: High g=1.3 s=3.35");
}
else if (params.icm.gamma=="Low_g2.6_s6.9") {
gammaStr = std::wstring(L"GammaTRC: Low g=2.6 s=6.9");
}
else if (params.icm.gamma=="sRGB_g2.4_s12.92") {
gammaStr = std::wstring(L"GammaTRC: sRGB g=2.4 s=12.92");
}
else if (params.icm.gamma== "BT709_g2.2_s4.5") {
gammaStr = std::wstring(L"GammaTRC: BT709 g=2.2 s=4.5");
}
else if (params.icm.gamma== "linear_g1.0") {
gammaStr = std::wstring(L"GammaTRC: Linear g=1.0");
}
else if (params.icm.gamma== "standard_g2.2") {
gammaStr = std::wstring(L"GammaTRC: g=2.2");
}
else if (params.icm.gamma== "standard_g1.8") {
gammaStr = std::wstring(L"GammaTRC: g=1.8");
}
cmsMLUsetWide(DescriptionMLU, "en", "US", gammaStr.c_str());
//for elaboration ICC profiles
// else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Medium gamma sRGB(AdobeRGB compatible)");
// else if (params.icm.gamma== "BT709_g2.2_s4.5" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma BT709(IEC61966 equivalent)");
// else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma sRGB(IEC61966 equivalent)");
// else if (params.icm.gamma== "linear_g1.0" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma Linear1.0(IEC61966 equivalent)");
//else if (params.icm.gamma== "BT709_g2.2_s4.5" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma BT709(Prophoto compatible)");
// else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma sRGB(Prophoto compatible)");
// else if (params.icm.gamma== "linear_g1.0" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma Linear1.0(Prophoto compatible)");
}
else {
// create description with gamma + slope + primaries
std::wostringstream gammaWs;
gammaWs.precision(2);
gammaWs<<"Manual GammaTRC: g="<<(float)params.icm.gampos<<" s="<<(float)params.icm.slpos;
cmsMLUsetWide(DescriptionMLU, "en", "US", gammaWs.str().c_str());
}
cmsWriteTag(jprof, cmsSigProfileDescriptionTag, DescriptionMLU);//desc changed
// cmsWriteTag(jprof, cmsSigCopyrightTag, CopyrightMLU);
// cmsWriteTag(jprof, cmsSigDeviceMfgDescTag, DmndMLU);
// cmsWriteTag(jprof, cmsSigDeviceModelDescTag, DmddMLU);
// Calculate output profile's rTRC bTRC gTRC
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters);
cmsWriteTag(jprof, cmsSigGreenTRCTag, (void*)GammaTRC[1] );
cmsWriteTag(jprof, cmsSigRedTRCTag, (void*)GammaTRC[0] );
cmsWriteTag(jprof, cmsSigBlueTRCTag, (void*)GammaTRC[2] );
//for generation ICC profiles : here Prophoto ==> Large
// if(params.icm.gamma== "BT709_g2.2_s4.5") cmsSaveProfileToFile(jprof, "RT_sRGB_gBT709.icm");
// else if (params.icm.gamma== "sRGB_g2.4_s12.92") cmsSaveProfileToFile(jprof, "RT_Medium_gsRGB.icc");
// else if (params.icm.gamma== "linear_g1.0") cmsSaveProfileToFile(jprof, "RT_Large_g10.icc");
}
}
if (GammaTRC[0]) cmsFreeToneCurve(GammaTRC[0]);
}
else {
// if Default gamma mode: we use the profile selected in the "Output profile" combobox;
// gamma come from the selected profile, otherwise it comes from "Free gamma" tool
// readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, params.blackwhite.enabled);
bool bwonly = params.blackwhite.enabled && !params.colorToning.enabled ;
if(autili || butili ) bwonly = false;
readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, bwonly);
if (settings->verbose) printf("Output profile_: \"%s\"\n", params.icm.output.c_str());
}
delete labView;
labView = NULL;
if(!autili && !butili ) {
if(params.blackwhite.enabled && !params.colorToning.enabled ) {//force BW r=g=b
if (settings->verbose) printf("Force BW\n");
for (int ccw=0;ccw<cw;ccw++) {
for (int cch=0;cch<ch;cch++) {
readyImg->r(cch,ccw)=readyImg->g(cch,ccw);
readyImg->b(cch,ccw)=readyImg->g(cch,ccw);
}
}
}
}
if (pl) pl->setProgress (0.70);
if (tmpScale != 1.0 && params.resize.method == "Nearest") { // resize rgb data (gamma applied)
Image16* tempImage = new Image16 (imw, imh);
ipf.resize (readyImg, tempImage, tmpScale);
delete readyImg;
readyImg = tempImage;
}
if (tunnelMetaData)
readyImg->setMetadata (ii->getMetaData()->getExifData ());
else
readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc);
// Setting the output curve to readyImg
if (customGamma) {
if (!useLCMS) {
// use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16b
ProfileContent pc(jprof);
readyImg->setOutputProfile (pc.data, pc.length);
}
}
else {
// use RT_sRGB.icm profile if present, otherwise use LCMS2 profile generate by lab2rgb16b
Glib::ustring outputProfile;
if (params.icm.output!="" && params.icm.output!=ColorManagementParams::NoICMString) {
outputProfile = params.icm.output;
/* if we'd wanted the RT_sRGB profile we would have selected it
else {
// use RT_sRGB.icm profile if present, otherwise use LCMS2 profile generate by lab2rgb16b
if (settings->verbose) printf("No output profiles set ; looking for the default sRGB profile (\"%s\")...\n", options.rtSettings.srgb.c_str());
outputProfile = options.rtSettings.srgb;
}*/
// if iccStore->getProfile send back an object, then iccStore->getContent will do too
cmsHPROFILE jprof = iccStore->getProfile(outputProfile); //get outProfile
if (jprof == NULL) {
if (settings->verbose) printf("\"%s\" ICC output profile not found!\n - use LCMS2 substitution\n", outputProfile.c_str());
}
else {
if (settings->verbose) printf("Using \"%s\" output profile\n", outputProfile.c_str());
ProfileContent pc = iccStore->getContent (outputProfile);
readyImg->setOutputProfile (pc.data, pc.length);
}
} else {
// No ICM
readyImg->setOutputProfile (NULL,0);
}
}
// t2.set();
// if( settings->verbose )
// printf("Total:- %d usec\n", t2.etime(t1));
if (!job->initialImage)
ii->decreaseRef ();
delete job;
if (pl)
pl->setProgress (0.75);
/* curve1.reset();curve2.reset();
curve.reset();
satcurve.reset();
lhskcurve.reset();
rCurve.reset();
gCurve.reset();
bCurve.reset();
hist16.reset();
hist16C.reset();
*/
return readyImg;
}
void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData) {
ProcessingJob* currentJob = job;
while (currentJob) {
int errorCode;
IImage16* img = processImage (currentJob, errorCode, bpl, tunnelMetaData, true);
if (errorCode) {
bpl->error (M("MAIN_MSG_CANNOTLOAD"));
currentJob = NULL;
} else {
try {
currentJob = bpl->imageReady (img);
} catch (Glib::Exception& ex) {
bpl->error (ex.what());
currentJob = NULL;
}
}
}
}
void startBatchProcessing (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData) {
if (bpl)
#if __GNUC__ == 4 && __GNUC_MINOR__ == 8 && defined( WIN32 ) && defined(__x86_64__)
// See Issue 2384 "Very bad response time on win7/64 using gcc 4.8 when queue is running"
Glib::Thread::create(sigc::bind(sigc::ptr_fun(batchProcessingThread), job, bpl, tunnelMetaData), 0, true, true, Glib::THREAD_PRIORITY_NORMAL);
#else
Glib::Thread::create(sigc::bind(sigc::ptr_fun(batchProcessingThread), job, bpl, tunnelMetaData), 0, true, true, Glib::THREAD_PRIORITY_LOW);
#endif
}
}