/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ #include "improccoordinator.h" #include "curves.h" #include "mytime.h" #include "refreshmap.h" #include "simpleprocess.h" #include "../rtgui/ppversion.h" #include "colortemp.h" namespace rtengine { extern const Settings* settings; ImProcCoordinator::ImProcCoordinator () : workimg(NULL), lastAwbEqual(0.), ipf(¶ms, true), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), hltonecurve(65536,0), shtonecurve(65536,2),//clip above tonecurve(65536,0),//,1); lumacurve(65536,0), chroma_acurve(65536,0), chroma_bcurve(65536,0), satcurve(65536,0), lhskcurve(65536,0), vhist16(65536), lhist16(65536), lhist16Cropped(65536), lhist16CAM(65536), lhist16CroppedCAM(65536), lhist16CCAM(65536), lhist16CroppedCCAM(65536), lhist16CCAMAF(65536), lhist16ClabAF(65536), histCropped(65536), lhist16Clad(65536),lhist16CroppedClad(65536), histRed(256), histRedRaw(256), histGreen(256), histGreenRaw(256), histBlue(256), histBlueRaw(256), histLuma(256), histChroma(256), histToneCurve(256), histLCurve(256), histCCurve(256), histLCAM(256), histCCAM(256), histClad(256), bcabhist(256), rCurve(), gCurve(), bCurve(), rcurvehist(256), rcurvehistCropped(256), rbeforehist(256), gcurvehist(256), gcurvehistCropped(256), gbeforehist(256), bcurvehist(256), bcurvehistCropped(256), bbeforehist(256), pW(-1), pH(-1), plistener(NULL), imageListener(NULL), aeListener(NULL), hListener(NULL),acListener(NULL), resultValid(false), changeSinceLast(0), updaterRunning(false), destroying(false) {} void ImProcCoordinator::assign (ImageSource* imgsrc) { this->imgsrc = imgsrc; } ImProcCoordinator::~ImProcCoordinator () { destroying = true; updaterThreadStart.lock (); if (updaterRunning && thread) thread->join (); mProcessing.lock(); mProcessing.unlock(); freeAll (); std::vector toDel = crops; for (size_t i=0; idecreaseRef (); updaterThreadStart.unlock (); } DetailedCrop* ImProcCoordinator::createCrop () { return new Crop (this); } // todo: bitmask containing desired actions, taken from changesSinceLast // cropCall: calling crop, used to prevent self-updates void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { mProcessing.lock (); int numofphases = 14; int readyphase = 0; ipf.setScale (scale); // Check if any detail crops need high detail. If not, take a fast path short cut bool highDetailNeeded = (todo & M_HIGHQUAL); if (!highDetailNeeded) { for (size_t i=0; iget_skip() == 1 ) { // skip=1 -> full resolution highDetailNeeded=true; break; } } RAWParams rp = params.raw; if( !highDetailNeeded ){ // if below 100% magnification, take a fast path rp.dmethod = RAWParams::methodstring[RAWParams::fast]; rp.ca_autocorrect = false; rp.hotdeadpix_filt = false; rp.ccSteps = 0; //rp.all_enhance = false; } progress ("Applying white balance, color correction & sRGB conversion...",100*readyphase/numofphases); // raw auto CA is bypassed if no high detail is needed, so we have to compute it when high detail is needed if ( (todo & M_PREPROC) || (!highDetailPreprocessComputed && highDetailNeeded)) { imgsrc->preprocess( rp, params.lensProf, params.coarse ); imgsrc->getRAWHistogram( histRedRaw, histGreenRaw, histBlueRaw ); if (highDetailNeeded) highDetailPreprocessComputed = true; else highDetailPreprocessComputed = false; } /* Demosaic is kicked off only when Detail considerations: accurate detail is not displayed yet needed based on preview specifics (driven via highDetailNeeded flag) OR HLR considerations: Color HLR alters rgb output of demosaic, so re-demosaic is needed when Color HLR is being turned off; if HLR is enabled and changing method *from* Color to any other method OR HLR gets disabled when Color method was selected */ // If high detail (=100%) is newly selected, do a demosaic update, since the last was just with FAST if ( (todo & M_RAW) || (!highDetailRawComputed && highDetailNeeded) || ( params.hlrecovery.enabled && params.hlrecovery.method!="Color" && imgsrc->IsrgbSourceModified()) || (!params.hlrecovery.enabled && params.hlrecovery.method=="Color" && imgsrc->IsrgbSourceModified())) { if (settings->verbose) printf("Demosaic %s\n",rp.dmethod.c_str()); imgsrc->demosaic( rp ); if (highDetailNeeded) { highDetailRawComputed = true; if (params.hlrecovery.enabled && params.hlrecovery.method=="Color") { todo |= M_INIT; } } else highDetailRawComputed = false; } if (todo & (M_INIT|M_LINDENOISE)) { MyMutex::MyLock lock(minit); // Also used in crop window imgsrc->HLRecovery_Global( params.hlrecovery ); // this handles Color HLRecovery if (settings->verbose) printf ("Applying white balance, color correction & sRBG conversion...\n"); 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") { if (lastAwbEqual != params.wb.equal) { double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); if (rm != -1.) { autoWB.update(rm, gm, bm, params.wb.equal); lastAwbEqual = params.wb.equal; } else { lastAwbEqual = -1.; autoWB.useDefaults(params.wb.equal); } //double rr,gg,bb; //autoWB.getMultipliers(rr,gg,bb); } currWB = autoWB; } params.wb.temperature = currWB.getTemp (); params.wb.green = currWB.getGreen (); int tr = TR_NONE; if (params.coarse.rotate==90) tr |= TR_R90; else if (params.coarse.rotate==180) tr |= TR_R180; else if (params.coarse.rotate==270) tr |= TR_R270; if (params.coarse.hflip) tr |= TR_HFLIP; if (params.coarse.vflip) tr |= TR_VFLIP; imgsrc->getFullSize (fw, fh, tr); PreviewProps pp (0, 0, fw, fh, scale); setScale (scale); imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm, params.raw); //ColorTemp::CAT02 (orig_prev, ¶ms) ; //imgsrc->convertColorSpace(orig_prev, params.icm, params.raw); if (todo & M_LINDENOISE) { //printf("denoising!\n"); if (scale==1 && params.dirpyrDenoise.enabled) { ipf.RGB_denoise(orig_prev, orig_prev, imgsrc->isRAW(), params.dirpyrDenoise, params.defringe, imgsrc->getDirPyrDenoiseExpComp()); } } imgsrc->convertColorSpace(orig_prev, params.icm, params.raw); ipf.firstAnalysis (orig_prev, ¶ms, vhist16, imgsrc->getGamma()); } readyphase++; progress ("Rotate / Distortion...",100*readyphase/numofphases); bool needstransform = ipf.needsTransform(); // Remove transformation if unneeded if (!needstransform && orig_prev!=oprevi) { delete oprevi; oprevi = orig_prev; } if (needstransform && orig_prev==oprevi) oprevi = new Imagefloat (pW, pH); if ((todo & M_TRANSFORM) && needstransform) ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), imgsrc->getRotateDegree(), false); readyphase++; progress ("Preparing shadow/highlight map...",100*readyphase/numofphases); if ((todo & M_BLURMAP) && params.sh.enabled) { double radius = sqrt (double(pW*pW+pH*pH)) / 2.0; double shradius = params.sh.radius; if (!params.sh.hq) shradius *= radius / 1800.0; shmap->update (oprevi, shradius, ipf.lumimul, params.sh.hq, scale); } readyphase++; if (todo & M_AUTOEXP) { if (params.toneCurve.autoexp) { LUTu aehist; int aehistcompr; imgsrc->getAutoExpHistogram (aehist, aehistcompr); ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); if (aeListener) aeListener->autoExpChanged (params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr,params.toneCurve.hlcomprthresh); } } progress ("Exposure curve & CIELAB conversion...",100*readyphase/numofphases); if ((todo & M_RGBCURVE) || todo==CROP) { if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); // complexCurve also calculated pre-curves histogram dependend on crop ipf.g = imgsrc->getGamma(); ipf.iGamma = true; CurveFactory::complexCurve (params.toneCurve.expcomp, params.toneCurve.black/65535.0, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, ipf.g, !ipf.iGamma, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, vhist16, histCropped, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale==1 ? 1 : 1); CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, scale==1 ? 1 : 1); CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, scale==1 ? 1 : 1); CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, scale==1 ? 1 : 1); // if it's just crop we just need the histogram, no image updates if ( todo!=CROP ) { ipf.rgbProc (oprevi, oprevl, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); } // compute L channel histogram int x1, y1, x2, y2, pos, poscc; params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); lhist16.clear(); lhist16Cropped.clear(); lhist16Clad.clear(); lhist16CroppedClad.clear(); lhist16ClabAF.clear(); for (int x=0; xL[x][y])); lhist16[pos]++; if (y>=y1 && y=x1 && xCopyFrom(oprevl); progress ("Applying Color Boost...",100*readyphase/numofphases); int poscc; ipf.chromiLuminanceCurve (pW,nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve,lhskcurve, lumacurve, utili, autili, butili, ccutili,cclutili, histCCurve); ipf.vibrance(nprevl); if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) ipf.EPDToneMap(nprevl,5,1); // for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled readyphase++; if (scale==1) { if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ progress ("Denoising luminance impulse...",100*readyphase/numofphases); ipf.impulsedenoise (nprevl); readyphase++; } if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ progress ("Defringing...",100*readyphase/numofphases); ipf.defringe (nprevl); readyphase++; } if (params.sharpenEdge.enabled) { progress ("Edge sharpening...",100*readyphase/numofphases); ipf.MLsharpen (nprevl); readyphase++; } if (params.sharpenMicro.enabled) { if(( params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ progress ("Microcontrast...",100*readyphase/numofphases); ipf.MLmicrocontrast (nprevl); readyphase++; } } if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) { progress ("Sharpening...",100*readyphase/numofphases); float **buffer = new float*[pH]; for (int i=0; iautocielab) || (!params.colorappearance.enabled)){ // if(params.colorappearance.enabled && !params.colorappearance.sharpcie){ progress ("Pyramid equalizer...",100*readyphase/numofphases); ipf.dirpyrequalizer (nprevl); readyphase++; } } //L histo and Chroma histo for ciecam // histogram well be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C int x1, y1, x2, y2, pos, posc; params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); lhist16CAM.clear(); lhist16CroppedCAM.clear(); lhist16CCAM.clear(); lhist16CroppedCCAM.clear(); lhist16CCAMAF.clear(); for (int x=0; xL[x][y])); posc=CLIP((int)sqrt(nprevl->a[x][y]*nprevl->a[x][y] + nprevl->b[x][y]*nprevl->b[x][y])); if(!params.colorappearance.datacie) lhist16CCAM[posc]++; if(!params.colorappearance.datacie)lhist16CAM[pos]++; if (y>=y1 && y=x1 && xgetMetaData()->getFNumber ();// F number float fiso = imgsrc->getMetaData()->getISOSpeed () ;// ISO float fspeed = imgsrc->getMetaData()->getShutterSpeed () ;//speed float fcomp = imgsrc->getMetaData()->getExpComp ();//compensation + - float adap2,adap; double ada, ada2; if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) {adap=adap=2000.f;ada=2000.;}//if no exif data or wrong else { float E_V = fcomp + log2 ((fnum*fnum) / fspeed / (fiso/100.f)); float expo2= params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV E_V += expo2; float expo1;//exposure raw white point expo1=log2(params.raw.expos);//log2 ==>linear to EV E_V += expo1; adap2 = adap= powf(2.f, E_V-3.f);//cd / m2 ada=ada2=(double) adap; //end calculation adaptation scene luminosity } int begh=0; int endh=pH; float d; double dd; float **buffer = new float*[pH]; for (int i=0; iciecamfloat){ipf.ciecam_02float (ncie, adap, begh, endh, pW, 2, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, execsharp, d); if(params.colorappearance.autodegree && acListener && params.colorappearance.enabled) acListener->autoCamChanged(100.*(double)d); if(params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) acListener->adapCamChanged(adap2);//real value of adapt scene luminosity } else {ipf.ciecam_02 (ncie, ada, begh, endh, pW, 2, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, execsharp, dd); if(params.colorappearance.autodegree && acListener && params.colorappearance.enabled) acListener->autoCamChanged(100.*dd); if(params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) acListener->adapCamChanged(ada); } for (int i=0; ihasListener () && cropCall != crops[i] ) crops[i]->update (todo); // may call ourselves progress ("Conversion to RGB...",100*readyphase/numofphases); if (todo!=CROP) { previmg->getMutex().lock(); try { ipf.lab2monitorRgb (nprevl, previmg); delete workimg; workimg = ipf.lab2rgb (nprevl, 0,0,pW,pH, params.icm.working); } catch(char * str) { progress ("Error converting file...",0); previmg->getMutex().unlock(); mProcessing.unlock (); return; } previmg->getMutex().unlock(); } if (!resultValid) { resultValid = true; if (imageListener) imageListener->setImage (previmg, scale, params.crop); } if (imageListener) // TODO: The WB tool should be advertised too in order to get the AutoWB's temp and green values imageListener->imageReady (params.crop); readyphase++; if (hListener) { updateLRGBHistograms (); hListener->histogramChanged (histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve,histCCurve, histLCAM, histCCAM, histRedRaw, histGreenRaw, histBlueRaw, histChroma); } mProcessing.unlock (); } void ImProcCoordinator::freeAll () { if (settings->verbose) printf ("freeall starts %d\n", (int)allocated); if (allocated) { if (orig_prev!=oprevi) delete oprevi; delete orig_prev; delete oprevl; delete nprevl; delete ncie; if (imageListener) { imageListener->delImage (previmg); } else delete previmg; delete workimg; delete shmap; } allocated = false; } void ImProcCoordinator::setScale (int prevscale) { if (settings->verbose) printf ("setscale before lock\n"); tr = TR_NONE; if (params.coarse.rotate==90) tr |= TR_R90; if (params.coarse.rotate==180) tr |= TR_R180; if (params.coarse.rotate==270) tr |= TR_R270; if (params.coarse.hflip) tr |= TR_HFLIP; if (params.coarse.vflip) tr |= TR_VFLIP; int nW, nH; imgsrc->getFullSize (fw, fh, tr); PreviewProps pp (0, 0, fw, fh, prevscale); imgsrc->getSize (tr, pp, nW, nH); if (settings->verbose) printf ("setscale starts (%d, %d)\n", nW, nH); if (nW!=pW || nH!=pH) { freeAll (); pW = nW; pH = nH; orig_prev = new Imagefloat (pW, pH); oprevi = orig_prev; oprevl = new LabImage (pW, pH); nprevl = new LabImage (pW, pH); ncie = new CieImage (pW, pH); previmg = new Image8 (pW, pH); workimg = new Image8 (pW, pH); shmap = new SHMap (pW, pH, true); allocated = true; } scale = prevscale; resultValid = false; fullw = fw; fullh = fh; if (settings->verbose) printf ("setscale ends\n"); if (!sizeListeners.empty()) for (size_t i=0; isizeChanged (fullw, fullh, fw, fh); if (settings->verbose) printf ("setscale ends2\n"); } void ImProcCoordinator::updateLRGBHistograms () { int x1, y1, x2, y2; params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); histRed.clear(); histGreen.clear(); histBlue.clear(); for (int i=y1; idata[ofs++]; int g=workimg->data[ofs++]; int b=workimg->data[ofs++]; histRed[r]++; histGreen[g]++; histBlue[b]++; } } histLuma.clear(); histChroma.clear(); for (int i=y1; ia[i][j]*nprevl->a[i][j] + nprevl->b[i][j]*nprevl->b[i][j]))/188]++;//188 = 48000/256 histLuma[(int)(nprevl->L[i][j]/128)]++; } /*for (int i=0; i<256; i++) { Lhist[i] = (int)(256*sqrt(Lhist[i])); rhist[i] = (int)(256*sqrt(rhist[i])); ghist[i] = (int)(256*sqrt(ghist[i])); bhist[i] = (int)(256*sqrt(bhist[i])); bcrgbhist[i] = (int)(256*sqrt(bcrgbhist[i])); bcLhist[i] = (int)(256*sqrt(bcLhist[i])); }*/ } void ImProcCoordinator::progress (Glib::ustring str, int pr) { /* if (plistener) { plistener->setProgressStr (str); plistener->setProgress ((double)pr / 100.0); }*/ } bool ImProcCoordinator::getAutoWB (double& temp, double& green, double equal) { if (imgsrc) { if (lastAwbEqual != equal) { MyMutex::MyLock lock(minit); // Also used in crop window double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); if (rm != -1) { autoWB.update(rm, gm, bm, equal); lastAwbEqual = equal; } else { lastAwbEqual = -1.; autoWB.useDefaults(equal); } } temp = autoWB.getTemp (); green = autoWB.getGreen (); return true; } else { //temp = autoWB.getTemp(); temp = -1.0; green = -1.0; return false; } } void ImProcCoordinator::getCamWB (double& temp, double& green) { if (imgsrc) { temp = imgsrc->getWB().getTemp (); green = imgsrc->getWB().getGreen (); } } void ImProcCoordinator::getSpotWB (int x, int y, int rect, double& temp, double& tgreen) { mProcessing.lock (); std::vector points, red, green, blue; for (int i=y-rect; i<=y+rect; i++) for (int j=x-rect; j<=x+rect; j++) points.push_back (Coord2D (j, i)); ipf.transCoord (fw, fh, points, red, green, blue); int tr = TR_NONE; if (params.coarse.rotate==90) tr |= TR_R90; if (params.coarse.rotate==180) tr |= TR_R180; if (params.coarse.rotate==270) tr |= TR_R270; if (params.coarse.hflip) tr |= TR_HFLIP; if (params.coarse.vflip) tr |= TR_VFLIP; ColorTemp ret = imgsrc->getSpotWB (red, green, blue, tr, params.wb.equal); currWB = ColorTemp (params.wb.temperature, params.wb.green,params.wb.equal, params.wb.method); //double rr,gg,bb; //currWB.getMultipliers(rr,gg,bb); mProcessing.unlock (); if (ret.getTemp() > 0) { temp = ret.getTemp (); tgreen = ret.getGreen (); } else { temp = currWB.getTemp (); tgreen = currWB.getGreen (); } } void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int &h) { mProcessing.lock (); LCPMapper *pLCPMap=NULL; if (params.lensProf.lcpFile.length() && imgsrc->getMetaData()->getFocalLen()>0) { LCPProfile *pLCPProf=lcpStore->getProfile(params.lensProf.lcpFile); if (pLCPProf) pLCPMap=new LCPMapper(pLCPProf, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), 0, false, params.lensProf.useDist, fullw, fullh, params.coarse, imgsrc->getRotateDegree()); } double fillscale = ipf.getTransformAutoFill (fullw, fullh, pLCPMap); if (ratio>0) { w = fullw * fillscale; h = w / ratio; if (h > fullh * fillscale) { h = fullh * fillscale; w = h * ratio; } } else { w = fullw * fillscale; h = fullh * fillscale; } x = (fullw - w) / 2; y = (fullh - h) / 2; mProcessing.unlock (); } void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) { mProcessing.lock (); int fW, fH; imgsrc->getFullSize (fW, fH, 0); PreviewProps pp (0, 0, fW, fH, 1); ProcParams ppar = params; ppar.hlrecovery.enabled = false; ppar.icm.input = "(none)"; Imagefloat* im = new Imagefloat (fW, fH); imgsrc->preprocess( ppar.raw, ppar.lensProf, ppar.coarse ); imgsrc->demosaic(ppar.raw ); //imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); 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") { if (lastAwbEqual != params.wb.equal) { double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); if (rm != -1.) { autoWB.update(rm, gm, bm, params.wb.equal); lastAwbEqual = params.wb.equal; } else { lastAwbEqual = -1.; autoWB.useDefaults(params.wb.equal); } } currWB = autoWB; } params.wb.temperature = currWB.getTemp (); params.wb.green = currWB.getGreen (); imgsrc->getImage (currWB, 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); imgsrc->convertColorSpace(im, ppar.icm, params.raw); Image16* im16 = im->to16(); delete im; im16->saveTIFF (fname,16,true); delete im16; //im->saveJPEG (fname, 85); mProcessing.unlock (); } void ImProcCoordinator::stopProcessing () { updaterThreadStart.lock (); if (updaterRunning && thread) { changeSinceLast = 0; thread->join (); } updaterThreadStart.unlock (); } void ImProcCoordinator::startProcessing () { #undef THREAD_PRIORITY_NORMAL if (!destroying) { updaterThreadStart.lock (); if (!updaterRunning) { thread = NULL; updaterRunning = true; updaterThreadStart.unlock (); //batchThread->yield(); //the running batch should wait other threads to avoid conflict thread = Glib::Thread::create(sigc::mem_fun(*this, &ImProcCoordinator::process), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); } else updaterThreadStart.unlock (); } } void ImProcCoordinator::startProcessing(int changeCode) { paramsUpdateMutex.lock(); changeSinceLast |= changeCode; paramsUpdateMutex.unlock(); startProcessing (); } void ImProcCoordinator::process () { if (plistener) plistener->setProgressState (true); paramsUpdateMutex.lock (); while (changeSinceLast) { params = nextParams; int change = changeSinceLast; changeSinceLast = 0; paramsUpdateMutex.unlock (); // M_VOID means no update, and is a bit higher that the rest if (change & (M_VOID-1)) updatePreviewImage (change); paramsUpdateMutex.lock (); } paramsUpdateMutex.unlock (); updaterRunning = false; if (plistener) plistener->setProgressState (false); } ProcParams* ImProcCoordinator::beginUpdateParams () { paramsUpdateMutex.lock (); return &nextParams; } void ImProcCoordinator::endUpdateParams (ProcEvent change) { endUpdateParams( refreshmap[(int)change] ); } void ImProcCoordinator::endUpdateParams (int changeFlags) { changeSinceLast |= changeFlags; paramsUpdateMutex.unlock (); startProcessing (); } }