/* * 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 #include #include #include #define CLIPTO(a,b,c) ((a)>b?((a)imgsrc = imgsrc; } ImProcCoordinator::~ImProcCoordinator () { destroying = true; updaterThreadStart.lock (); if (updaterRunning && thread) thread->join (); mProcessing.lock(); mProcessing.unlock(); freeAll (); std::vector toDel = crops; for (int i=0; idecreaseRef (); ipf.release (); updaterThreadStart.unlock (); } DetailedCrop* ImProcCoordinator::createCrop () { return new Crop (this); } void ImProcCoordinator::updatePreviewImage (int todo) { mProcessing.lock (); MyTime t1,t2,t3,t4,t5,t6,t7,t8,t9; t1.set (); int numofphases = 10; int readyphase = 0; if (!params.resize.enabled) params.resize.scale = 1.0; else if (params.resize.dataspec==1) params.resize.scale = (double)params.resize.width / (params.coarse.rotate==90 || params.coarse.rotate==270 ? fh : fw); else if (params.resize.dataspec==2) params.resize.scale = (double)params.resize.height / (params.coarse.rotate==90 || params.coarse.rotate==270 ? fw : fh); progress ("Applying white balance, color correction & sRBG conversion...",100*readyphase/numofphases); if (todo & M_INIT) { minit.lock (); if (settings->verbose) printf ("Applying white balance, color correction & sRBG conversion...\n"); currWB = ColorTemp (params.wb.temperature, params.wb.green); if (params.wb.method=="Camera") currWB = imgsrc->getWB (); else if (params.wb.method=="Auto") { if (!awbComputed) { autoWB = imgsrc->getAutoWB (); awbComputed = true; } currWB = autoWB; } params.wb.temperature = currWB.getTemp (); params.wb.green = currWB.getGreen (); 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; imgsrc->getFullSize (fw, fh, tr); PreviewProps pp (0, 0, fw, fh, scale); setScale (scale, true); imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm); ipf.firstAnalysis (orig_prev, ¶ms, vhist16, imgsrc->getGamma()); minit.unlock (); } t2.set (); if (settings->verbose) printf ("INIT: %d\n", t2.etime(t1)); readyphase++; progress ("Rotate / Distortion...",100*readyphase/numofphases); // printf ("ROTSTAT: %g, %g, %d, %d\n", params.rotate.degree, params.distortion.amount, (int)orig_prev, (int)oprevi); // check if the transformation has been switched off: bool needstransform = fabs(params.rotate.degree)>1e-15 || fabs(params.distortion.amount)>1e-15 || fabs(params.cacorrection.red)>1e-15 || fabs(params.cacorrection.blue)>1e-15; bool needsvignetting = params.vignetting.amount!=0; if (!needstransform && !needsvignetting && orig_prev!=oprevi) { delete oprevi; oprevi = orig_prev; } // check if the transformation has been switched on: else if ((needstransform || needsvignetting) && orig_prev==oprevi) { oprevi = new Image16 (pW, pH); } if ((todo & M_TRANSFORM) && !needstransform && needsvignetting) ipf.vignetting (orig_prev, oprevi, ¶ms, 0, 0, pW, pH); else if ((todo & M_TRANSFORM) && needstransform) if (scale==1) ipf.transform (orig_prev, oprevi, ¶ms, 0, 0, 0, 0, pW, pH); else ipf.simpltransform (orig_prev, oprevi, ¶ms, 0, 0, 0, 0, pW, pH); t3.set (); if (settings->verbose) printf ("TRANSFORM: %d\n", t3.etime(t2)); 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 = radius / 1800.0 * params.sh.radius; shmap->update (oprevi, (unsigned short**)buffer, shradius, ipf.lumimul, params.sh.hq); } t4.set (); if (settings->verbose) printf ("BLURMAP: %d\n", t4.etime(t3)); readyphase++; if (todo & M_AUTOEXP) { if (params.toneCurve.autoexp) { unsigned int aehist[65536]; int aehistcompr; imgsrc->getAEHistogram (aehist, aehistcompr); ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, params.toneCurve.expcomp, params.toneCurve.black); if (aeListener) aeListener->autoExpChanged (params.toneCurve.expcomp, params.toneCurve.black); } } progress ("Exposure curve & CIELAB conversion...",100*readyphase/numofphases); if (todo & M_RGBCURVE) { CurveFactory::complexCurve (params.toneCurve.expcomp, params.toneCurve.black/65535.0, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getDefGain(), imgsrc->getGamma(), true, params.toneCurve.curve, vhist16, tonecurve, bcrgbhist, scale==1 ? 1 : 1); ipf.rgbProc (oprevi, oprevl, ¶ms, tonecurve, shmap); // recompute luminance histogram memset (lhist16, 0, 65536*sizeof(int)); for (int i=0; iL[i][j]]++; } t5.set (); if (settings->verbose) printf ("RGB: %d\n", t5.etime(t4)); readyphase++; if (todo & M_LUMACURVE) { CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, params.lumaCurve.brightness, params.lumaCurve.contrast, 0.0, 0.0, false, params.lumaCurve.curve, lhist16, lumacurve, bcLhist, scale==1 ? 1 : 16); } if (todo & M_LUMINANCE) { progress ("Applying Luminance Curve...",100*readyphase/numofphases); ipf.luminanceCurve (oprevl, nprevl, lumacurve, 0, pH); readyphase++; if (scale==1) { progress ("Denoising luminance...",100*readyphase/numofphases); ipf.lumadenoise (nprevl, ¶ms, scale*params.resize.scale, buffer); } readyphase++; if (scale==1) { progress ("Sharpening...",100*readyphase/numofphases); ipf.sharpening (nprevl, ¶ms, scale*params.resize.scale, (unsigned short**)buffer); } readyphase++; } t6.set (); if (settings->verbose) printf ("LUMINANCE: %d\n", t6.etime(t5)); if (todo & M_COLOR) { progress ("Applying Color Boost...",100*readyphase/numofphases); ipf.colorCurve (oprevl, nprevl, ¶ms); readyphase++; if (scale==1) { progress ("Denoising color...",100*readyphase/numofphases); ipf.colordenoise (nprevl, ¶ms, scale*params.resize.scale, buffer); } readyphase++; } t7.set (); if (settings->verbose) printf ("COLOR: %d\n", t7.etime(t6)); // process crop, if needed for (int i=0; ihasListener ()) crops[i]->update (todo, true); progress ("Conversion to RGB...",100*readyphase/numofphases); if (todo!=CROP) { previmg->getMutex().lock(); ipf.lab2rgb (nprevl, previmg); previmg->getMutex().unlock(); } if (!resultValid) { resultValid = true; if (imageListener) imageListener->setImage (previmg, scale*params.resize.scale, params.crop); } if (imageListener) imageListener->imageReady (params.crop); readyphase++; t8.set (); if (settings->verbose) printf ("RGBCONVERT: %d\n", t8.etime(t7)); if (hListener) { int hx1 = 0, hx2 = pW, hy1 = 0, hy2 = pH; if (params.crop.enabled) { hx1 = MIN(pW-1,MAX(0,params.crop.x / scale)); hy1 = MIN(pH-1,MAX(0,params.crop.y / scale)); hx2 = MIN(pW,MAX(0,(params.crop.x+params.crop.w) / scale)); hy2 = MIN(pH,MAX(0,(params.crop.y+params.crop.h) / scale)); } updateHistograms (hx1, hy1, hx2, hy2); hListener->histogramChanged (rhist, ghist, bhist, Lhist, bcrgbhist, bcLhist); } t9.set (); if (settings->verbose) printf ("Total processing time: %d\n", t9.etime(t1)); progress ("Ready",100*readyphase/numofphases); 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; if (imageListener) { imageListener->delImage (previmg); } else delete previmg; delete shmap; for (int i=0; iverbose) printf ("setscale before lock\n"); if (!internal) mProcessing.lock (); 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 Image16 (pW, pH); oprevi = orig_prev; oprevl = new LabImage (pW, pH); nprevl = new LabImage (pW, pH); previmg = new Image8 (pW, pH); shmap = new SHMap (pW, pH); buffer = new int*[pH]; for (int i=0; iverbose) printf ("setscale ends\n"); if (sizeListeners.size()>0) for (int i=0; isizeChanged (fullw, fullh, fw, fh); if (settings->verbose) printf ("setscale ends2\n"); if (!internal) mProcessing.unlock (); } void ImProcCoordinator::updateHistograms (int x1, int y1, int x2, int y2) { memset (rhist, 0, 256*sizeof(int)); memset (ghist, 0, 256*sizeof(int)); memset (bhist, 0, 256*sizeof(int)); for (int i=y1; idata[ofs++]]++; ghist[previmg->data[ofs++]]++; bhist[previmg->data[ofs++]]++; } } memset (Lhist, 0, 256*sizeof(int)); for (int i=y1; iL[i][j]/256]++; } void ImProcCoordinator::progress (Glib::ustring str, int pr) { /* if (plistener) { plistener->setProgressStr (str); plistener->setProgress ((double)pr / 100.0); }*/ } void ImProcCoordinator::getAutoWB (double& temp, double& green) { if (imgsrc) { if (!awbComputed) { minit.lock (); autoWB = imgsrc->getAutoWB (); minit.unlock (); awbComputed = true; } temp = autoWB.getTemp (); green = autoWB.getGreen (); } } 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 (¶ms, 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); mProcessing.unlock (); temp = ret.getTemp (); tgreen = ret.getGreen (); } void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int &h) { mProcessing.lock (); w = fullw; bool clipped = true; while (clipped && w>16) { if (ratio>0) h = w / ratio; else h = w * fullh / fullw; x = (fullw - w) / 2; y = (fullh - h) / 2; int orx, ory, orw, orh; clipped = ipf.transCoord (¶ms, fw, fh, x, y, w, h, orx, ory, orw, orh); w -= 4; } if (ratio>0) h = w / ratio; else h = w * fullh / fullw; x = (fullw - w) / 2; y = (fullh - h) / 2; mProcessing.unlock (); } void ImProcCoordinator::fullUpdatePreviewImage () { if (destroying) return; updaterThreadStart.lock (); if (updaterRunning && thread) { changeSinceLast = 0; thread->join (); } if (plistener) plistener->setProgressState (1); updatePreviewImage (ALL); if (plistener) plistener->setProgressState (0); updaterThreadStart.unlock (); } void ImProcCoordinator::fullUpdateDetailedCrops () { if (destroying) return; updaterThreadStart.lock (); if (updaterRunning && thread) { changeSinceLast = 0; thread->join (); } if (plistener) plistener->setProgressState (1); for (int i=0; iupdate (ALL, true); if (plistener) plistener->setProgressState (0); updaterThreadStart.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)"; Image16* im = new Image16 (fW, fH); imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm); 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 (); thread = Glib::Thread::create(sigc::mem_fun(*this, &ImProcCoordinator::process), 0, false, true, Glib::THREAD_PRIORITY_NORMAL); } else updaterThreadStart.unlock (); } } void ImProcCoordinator::process () { if (plistener) plistener->setProgressState (1); paramsUpdateMutex.lock (); while (changeSinceLast) { params = nextParams; int ch = changeSinceLast; changeSinceLast = 0; paramsUpdateMutex.unlock (); if (ch&32767) updatePreviewImage (ch); paramsUpdateMutex.lock (); } paramsUpdateMutex.unlock (); updaterRunning = false; if (plistener) plistener->setProgressState (0); } ProcParams* ImProcCoordinator::getParamsForUpdate (ProcEvent change) { paramsUpdateMutex.lock (); changeSinceLast |= refreshmap[(int)change]; return &nextParams; } void ImProcCoordinator::paramsUpdateReady () { paramsUpdateMutex.unlock (); startProcessing (); } }