From 053b305d8947ea9ac5c36da87c767836c914fa9e Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 23 Nov 2016 17:23:25 +0100 Subject: [PATCH 1/6] Tone curve histogram ignores DCP tone curve, fixes #3512 --- rtengine/dcrop.cc | 3 ++- rtengine/improccoordinator.cc | 2 +- rtengine/improcfun.cc | 38 +++++++++++++++++++++++++++++++---- rtengine/improcfun.h | 4 ++-- rtengine/rtthumbnail.cc | 3 ++- rtengine/simpleprocess.cc | 4 +++- 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index e308ab13b..5e3ef6991 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -751,10 +751,11 @@ void Crop::update (int todo) DCPProfile::ApplyState as; DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, parent->currWB, as); + LUTu histToneCurve; parent->ipf.rgbProc (baseCrop, laboCrop, this, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, cshmap, params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->colourToningSatLimit , parent->colourToningSatLimitOpacity, parent->ctColorCurve, parent->ctOpacityCurve, parent->opautili, parent->clToningcurve, parent->cl2Toningcurve, parent->customToneCurve1, parent->customToneCurve2, parent->beforeToneCurveBW, parent->afterToneCurveBW, rrm, ggm, bbm, - parent->bwAutoR, parent->bwAutoG, parent->bwAutoB, dcpProf, as); + parent->bwAutoR, parent->bwAutoG, parent->bwAutoB, dcpProf, as, histToneCurve); } /*xref=000;yref=000; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index ca1d44cbf..1b546669a 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -539,7 +539,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); ipf.rgbProc (oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, - rCurve, gCurve, bCurve, colourToningSatLimit , colourToningSatLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, dcpProf, as); + rCurve, gCurve, bCurve, colourToningSatLimit , colourToningSatLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, dcpProf, as, histToneCurve); if(params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { if (settings->verbose) { diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 586243391..3e0433197 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -2948,15 +2948,15 @@ filmlike_clip(float *r, float *g, float *b) void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve, - const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn ) + const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve ) { - rgbProc (working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf, asIn); + rgbProc (working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf, asIn, histToneCurve); } // Process RGB image and convert to LAB space void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve, - const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn ) + const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve ) { BENCHFUN Imagefloat *tmpImage = nullptr; @@ -3030,6 +3030,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer {wprof[2][0], wprof[2][1], wprof[2][2]} }; + // For tonecurve histogram + float lumimulf[3] = {static_cast(lumimul[0]), static_cast(lumimul[1]), static_cast(lumimul[2])}; + bool mixchannels = (params->chmixer.red[0] != 100 || params->chmixer.red[1] != 0 || params->chmixer.red[2] != 0 || params->chmixer.green[0] != 0 || params->chmixer.green[1] != 100 || params->chmixer.green[2] != 0 || @@ -3282,6 +3285,16 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int W = working->width; int H = working->height; + // For tonecurve histogram + int toneCurveHistSize = histToneCurve ? histToneCurve.getSize() : 0; + int histToneCurveCompression; + + if(toneCurveHistSize > 0) { + histToneCurve.clear(); + histToneCurveCompression = log2(65536 / toneCurveHistSize); + } + + #define TS 112 #ifdef _OPENMP @@ -3325,6 +3338,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float out_rgbx[4 * TS] ALIGNED16; // Line buffer for CLUT + LUTu histToneCurveThr; + if(toneCurveHistSize > 0) { + histToneCurveThr(toneCurveHistSize); + histToneCurveThr.clear(); + } + #ifdef _OPENMP #pragma omp for schedule(dynamic) collapse(2) #endif @@ -3473,6 +3492,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(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]++; + } } } @@ -4398,7 +4421,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (editWhateverBuffer) { free (editWhateverBuffer); } - +#ifdef _OPENMP +#pragma omp critical +{ + if(toneCurveHistSize > 0) { + histToneCurve += histToneCurveThr; + } +} +#endif // _OPENMP } // starting a new tile processing with a 'reduction' clause for the auto mixer computing diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 5af2093d9..6a182e67b 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -208,11 +208,11 @@ public: void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck); void rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, - const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn ); + const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve ); void rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, - double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn ); + double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve); void labtoning (float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, LUTf & clToningcurve, LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3] ); void toning2col (float r, float g, float b, float &ro, float &go, float &bo, float iplow, float iphigh, float rl, float gl, float bl, float rh, float gh, float bh, float SatLow, float SatHigh, float balanS, float balanH, float reducac, int mode, int preser, float strProtect); void toningsmh (float r, float g, float b, float &ro, float &go, float &bo, float RedLow, float GreenLow, float BlueLow, float RedMed, float GreenMed, float BlueMed, float RedHigh, float GreenHigh, float BlueHigh, float reducac, int mode, int preser, float strProtect); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index c135acc39..4710f3fe8 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -1057,7 +1057,8 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei } } - ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as); + LUTu histToneCurve; + ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as, histToneCurve); // freeing up some memory customToneCurve1.Reset(); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 9e7d5f58f..4fb193c2b 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -858,7 +858,9 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p DCPProfile::ApplyState as; DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); - ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as); + LUTu histToneCurve; + + ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as, histToneCurve); if (settings->verbose) { printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); From c5bef4f3bcb3aa719333d2b24880f3bb5e74ad74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Mon, 28 Nov 2016 20:57:19 +0100 Subject: [PATCH 2/6] Make `ImageIO` load grayscale JPGs and TIFFs (#3515) --- rtengine/imageio.cc | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index f869a0f3e..e886dabce 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -556,11 +556,13 @@ int ImageIO::loadJPEG (Glib::ustring fname) jpeg_read_header(&cinfo, TRUE); //if JPEG is CMYK, then abort reading - if (cinfo.jpeg_color_space == JCS_CMYK || cinfo.jpeg_color_space == JCS_YCCK || cinfo.jpeg_color_space == JCS_GRAYSCALE) { + if (cinfo.jpeg_color_space == JCS_CMYK || cinfo.jpeg_color_space == JCS_YCCK) { jpeg_destroy_decompress(&cinfo); return IMIO_READERROR; } + cinfo.out_color_space = JCS_RGB; + deleteLoadedProfileData(); loadedProfileDataJpg = true; bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); @@ -677,8 +679,8 @@ int ImageIO::getTIFFSampleFormat (Glib::ustring fname, IIOSampleFormat &sFormat, TIFFClose(in); - if (photometric == PHOTOMETRIC_RGB) { - if ((samplesperpixel == 3 || samplesperpixel == 4) && sampleformat == SAMPLEFORMAT_UINT) { + if (photometric == PHOTOMETRIC_RGB || photometric == PHOTOMETRIC_MINISBLACK) { + if ((samplesperpixel == 1 || samplesperpixel == 3 || samplesperpixel == 4) && sampleformat == SAMPLEFORMAT_UINT) { if (bitspersample == 8) { sFormat = IIOSF_UNSIGNED_CHAR; return IMIO_SUCCESS; @@ -820,7 +822,7 @@ int ImageIO::loadTIFF (Glib::ustring fname) allocate (width, height); float minValue[3] = {0.f, 0.f, 0.f}, maxValue[3] = {0.f, 0.f, 0.f}; - unsigned char* linebuffer = new unsigned char[TIFFScanlineSize(in)]; + unsigned char* linebuffer = new unsigned char[TIFFScanlineSize(in) * (samplesperpixel == 1 ? 3 : 1)]; for (int row = 0; row < height; row++) { if (TIFFReadScanline(in, linebuffer, row, 0) < 0) { @@ -829,10 +831,21 @@ int ImageIO::loadTIFF (Glib::ustring fname) return IMIO_READERROR; } - if (samplesperpixel > 3) + if (samplesperpixel > 3) { for (int i = 0; i < width; i++) { memcpy (linebuffer + i * 3 * bitspersample / 8, linebuffer + i * samplesperpixel * bitspersample / 8, 3 * bitspersample / 8); } + } + else if (samplesperpixel == 1) { + const size_t bytes = bitspersample / 8; + for (int i = width - 1; i >= 0; --i) { + const unsigned char* const src = linebuffer + i * bytes; + unsigned char* const dest = linebuffer + i * 3 * bytes; + memcpy(dest + 2 * bytes, src, bytes); + memcpy(dest + 1 * bytes, src, bytes); + memcpy(dest + 0 * bytes, src, bytes); + } + } if (sampleFormat & (IIOSF_LOGLUV24 | IIOSF_LOGLUV32 | IIOSF_FLOAT)) { setScanline (row, linebuffer, bitspersample, minValue, maxValue); From 981a53492010a50fd9b2a334b4c130ca3799b7ae Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 29 Nov 2016 13:11:42 +0100 Subject: [PATCH 3/6] Fixes #3517, build fails when using libcairo 1.15 --- rtgui/guiutils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 38f5297eb..b8e058eb4 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -437,7 +437,7 @@ public: // you have to check if the surface is created thanks to surfaceCreated before starting to draw on it bool surfaceCreated() { - return surface; + return static_cast(surface); } Cairo::RefPtr getSurface() { From 976fc087bd52e8759e81bb7962fc66ea86b73ae9 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sat, 3 Dec 2016 11:24:11 +0100 Subject: [PATCH 4/6] Removed some debug message left in code --- rtengine/iplab2rgb.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 6b04bb8f2..218dbf6fe 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -169,9 +169,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; if (icm.outputBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; - printf("lab2rgb / bpc=true\n"); } - else printf("lab2rgb / bpc=false\n"); lcmsMutex->lock (); cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr); cmsHTRANSFORM hTransform = cmsCreateTransform (LabIProf, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, icm.outputIntent, flags); // NOCACHE is important for thread safety @@ -290,19 +288,15 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int iccStore->getGammaArray(icm, *ga); oprof = iccStore->createGammaProfile(icm, *ga); lcmsMutex->unlock (); - printf("iccStore->createGammaProfile(icm, *ga);\n"); } else { oprof = iccStore->getProfile (icm.output); -// printf("iccStore->getProfile (%s);\n", icm.output.c_str()); } if (oprof) { cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; if (icm.outputBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; -// printf("lab2rgb16 / icm.outputBPC=true / outputIntent=%d\n", icm.outputIntent); } -// else printf("lab2rgb16 / icm.outputBPC=false / outputIntent=%d\n", icm.outputIntent); lcmsMutex->lock (); cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_16, icm.outputIntent, flags); From 1f080e0438e8e88270f8cd5612d86e724d699efb Mon Sep 17 00:00:00 2001 From: Hombre Date: Sun, 11 Dec 2016 17:17:36 +0100 Subject: [PATCH 5/6] Bugfix: RT could crash while displaying Color Pickers (no issue) --- rtgui/cropwindow.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 10b188a21..20dd3eb9d 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -2083,10 +2083,15 @@ void CropWindow::updateHoveredPicker (rtengine::Coord *imgPos) } LockableColorPicker::Validity validity = checkValidity (hoveredPicker, cropPos); hoveredPicker->setValidity (validity); + + { + MyMutex::MyLock lock(cropHandler.cimg); + if (validity == LockableColorPicker::Validity::INSIDE) { cropHandler.colorPick(cropPos, r, g, b, rpreview, gpreview, bpreview, hoveredPicker->getSize()); hoveredPicker->setRGB (r, g, b, rpreview, gpreview, bpreview); } + } } void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery) { @@ -2450,6 +2455,7 @@ void CropWindow::drawObservedFrame (Cairo::RefPtr cr, int rw, in void CropWindow::cropImageUpdated () { + MyMutex::MyLock lock(cropHandler.cimg); for (auto colorPicker : colorPickers) { Coord imgPos, cropPos; From 23f17bd9bc0d1413e3919285b23e5dd978429676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Tue, 13 Dec 2016 20:44:05 +0100 Subject: [PATCH 6/6] Fully check thumb data size (#3529) Also, take rotation into account when falling back to `Thumbnail::loadFromRaw()`. --- rtengine/rawimage.h | 16 ++++++++-------- rtengine/rtthumbnail.cc | 41 +++++++++++++++++++++++++++++++++++++---- rtgui/cropwindow.cc | 10 +++++----- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 88ef5d710..b741a7ffc 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -274,37 +274,37 @@ public: { return profile_data; } - IMFILE *get_file() + IMFILE *get_file() const { return ifp; } bool is_supportedThumb() const ; bool is_jpegThumb() const ; bool is_ppmThumb() const ; - int get_thumbOffset() + int get_thumbOffset() const { return int(thumb_offset); } - int get_thumbWidth() + int get_thumbWidth() const { return int(thumb_width); } - int get_thumbHeight() + int get_thumbHeight() const { return int(thumb_height); } - int get_thumbBPS() + int get_thumbBPS() const { return thumb_load_raw ? 16 : 8; } bool get_thumbSwap() const; - unsigned get_thumbLength() + unsigned get_thumbLength() const { return thumb_length; } - bool zeroIsBad() + bool zeroIsBad() const { - return zero_is_bad == 1 ? true : false; + return zero_is_bad == 1; } public: diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 4710f3fe8..77e260985 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -41,6 +41,25 @@ #include "StopWatch.h" +namespace +{ + + bool checkRawImageThumb(const rtengine::RawImage& raw_image) + { + if (!raw_image.is_supportedThumb()) { + return false; + } + + const std::size_t length = + fdata(raw_image.get_thumbOffset(), raw_image.get_file())[1] != 0xD8 && raw_image.is_ppmThumb() + ? raw_image.get_thumbWidth() * raw_image.get_thumbHeight() * (raw_image.get_thumbBPS() / 8) * 3 + : raw_image.get_thumbLength(); + + return raw_image.get_thumbOffset() + length < raw_image.get_file()->size; + } + +} + extern Options options; namespace rtengine @@ -175,8 +194,8 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL int err = 1; - // see if it is something we support - if ( ri->is_supportedThumb() && ri->get_thumbOffset() < ri->get_file()->size ) { + // See if it is something we support + if (checkRawImageThumb(*ri)) { const char* data((const char*)fdata(ri->get_thumbOffset(), ri->get_file())); if ( (unsigned char)data[1] == 0xd8 ) { @@ -491,6 +510,17 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati tmph = high; } + const bool rotate_90 = + rotate + && ( + ri->get_rotateDegree() == 90 + || ri->get_rotateDegree() == 270 + ); + + if (rotate_90) { + std::swap(tmpw, tmph); + } + if (fixwh == 1) { // fix height, scale width w = tmpw * h / tmph; } else { @@ -501,8 +531,11 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati delete tpp->thumbImg; } - tpp->thumbImg = nullptr; - tpp->thumbImg = resizeTo(w, h, TI_Bilinear, tmpImg); + if (rotate_90) { + tpp->thumbImg = resizeTo(h, w, TI_Bilinear, tmpImg); + } else { + tpp->thumbImg = resizeTo(w, h, TI_Bilinear, tmpImg); + } delete tmpImg; diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 20dd3eb9d..0fc3359bc 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -2085,12 +2085,12 @@ void CropWindow::updateHoveredPicker (rtengine::Coord *imgPos) hoveredPicker->setValidity (validity); { - MyMutex::MyLock lock(cropHandler.cimg); + MyMutex::MyLock lock(cropHandler.cimg); - if (validity == LockableColorPicker::Validity::INSIDE) { - cropHandler.colorPick(cropPos, r, g, b, rpreview, gpreview, bpreview, hoveredPicker->getSize()); - hoveredPicker->setRGB (r, g, b, rpreview, gpreview, bpreview); - } + if (validity == LockableColorPicker::Validity::INSIDE) { + cropHandler.colorPick(cropPos, r, g, b, rpreview, gpreview, bpreview, hoveredPicker->getSize()); + hoveredPicker->setRGB (r, g, b, rpreview, gpreview, bpreview); + } } } void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery)