1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2004-07-29
7  * Description : image levels manipulation methods.
8  *
9  * Copyright (C) 2004-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  *
11  * This program is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation;
14  * either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 /**
25  * Map RGB to intensity
26  */
27 #define LEVELS_RGB_INTENSITY_RED    0.30
28 #define LEVELS_RGB_INTENSITY_GREEN  0.59
29 #define LEVELS_RGB_INTENSITY_BLUE   0.11
30 #define LEVELS_RGB_INTENSITY(r,g,b) ((r) * LEVELS_RGB_INTENSITY_RED   + \
31                                      (g) * LEVELS_RGB_INTENSITY_GREEN + \
32                                      (b) * LEVELS_RGB_INTENSITY_BLUE)
33 
34 #include "imagelevels.h"
35 
36 // Qt includes
37 
38 #include <QFile>
39 
40 // C++ includes
41 
42 #include <cstdio>
43 #include <cmath>
44 #include <cstring>
45 #include <cstdlib>
46 #include <cerrno>
47 
48 // Local includes
49 
50 #include "digikam_debug.h"
51 #include "digikam_config.h"
52 #include "imagehistogram.h"
53 #include "digikam_globals.h"
54 
55 namespace Digikam
56 {
57 
58 class Q_DECL_HIDDEN ImageLevels::Private
59 {
60 
61 public:
62 
63     enum PixelType
64     {
65         RedPixel = 0,
66         GreenPixel,
67         BluePixel,
68         AlphaPixel
69     };
70 
71     struct Q_DECL_HIDDEN _Levels
72     {
73         double gamma[5]         = { 0.0 };
74 
75         int    low_input[5]     = { 0 };
76         int    high_input[5]    = { 0 };
77 
78         int    low_output[5]    = { 0 };
79         int    high_output[5]   = { 0 };
80     };
81 
82     struct Q_DECL_HIDDEN _Lut
83     {
84         unsigned short** luts      = nullptr;
85         int              nchannels = 0;
86     };
87 
88 public:
89 
Private()90     explicit Private()
91       : levels      (nullptr),
92         lut         (nullptr),
93         sixteenBit  (false),
94         dirty       (false)
95     {
96     }
97 
98     /// Levels data.
99     _Levels* levels;
100 
101     /// Lut data.
102     _Lut*    lut;
103 
104     bool     sixteenBit;
105     bool     dirty;
106 };
107 
ImageLevels(bool sixteenBit)108 ImageLevels::ImageLevels(bool sixteenBit)
109     : d(new Private)
110 {
111     d->lut            = new Private::_Lut;
112     d->levels         = new Private::_Levels;
113     d->sixteenBit     = sixteenBit;
114     d->lut->luts      = nullptr;
115     d->lut->nchannels = 0;
116 
117     reset();
118 }
119 
~ImageLevels()120 ImageLevels::~ImageLevels()
121 {
122     if (d->lut)
123     {
124         if (d->lut->luts)
125         {
126             for (int i = 0 ; i < d->lut->nchannels ; ++i)
127             {
128                 delete [] d->lut->luts[i];
129             }
130 
131             delete [] d->lut->luts;
132         }
133 
134         delete d->lut;
135     }
136 
137     if (d->levels)
138     {
139         delete d->levels;
140     }
141 
142     delete d;
143 }
144 
isDirty()145 bool ImageLevels::isDirty()
146 {
147     return d->dirty;
148 }
149 
isSixteenBits()150 bool ImageLevels::isSixteenBits()
151 {
152     return d->sixteenBit;
153 }
154 
reset()155 void ImageLevels::reset()
156 {
157     for (int channel = 0 ; channel < 5 ; ++channel)
158     {
159         levelsChannelReset(channel);
160     }
161 }
162 
levelsChannelReset(int channel)163 void ImageLevels::levelsChannelReset(int channel)
164 {
165     if (!d->levels)
166     {
167         return;
168     }
169 
170     d->levels->gamma[channel]       = 1.0;
171     d->levels->low_input[channel]   = 0;
172     d->levels->high_input[channel]  = d->sixteenBit ? 65535 : 255;
173     d->levels->low_output[channel]  = 0;
174     d->levels->high_output[channel] = d->sixteenBit ? 65535 : 255;
175     d->dirty = false;
176 }
177 
levelsAuto(ImageHistogram * const hist)178 void ImageLevels::levelsAuto(ImageHistogram* const hist)
179 {
180     if (!d->levels || !hist)
181     {
182         return;
183     }
184 
185     levelsChannelReset(LuminosityChannel);
186 
187     for (int channel = RedChannel ; channel <= BlueChannel ; ++channel)
188     {
189         levelsChannelAuto(hist, channel);
190     }
191 
192     d->dirty = true;
193 }
194 
levelsChannelAuto(ImageHistogram * const hist,int channel)195 void ImageLevels::levelsChannelAuto(ImageHistogram* const hist, int channel)
196 {
197     if (!d->levels || !hist)
198     {
199         return;
200     }
201 
202     d->levels->gamma[channel]       = 1.0;
203     d->levels->low_output[channel]  = 0;
204     d->levels->high_output[channel] = d->sixteenBit ? 65535 : 255;
205     double count                    = hist->getCount(channel, 0, d->sixteenBit ? 65535 : 255);
206 
207     if (count == 0.0)
208     {
209         d->levels->low_input[channel]  = 0;
210         d->levels->high_input[channel] = 0;
211     }
212     else
213     {
214         //  Set the low input
215 
216         double new_count       = 0.0;
217         double percentage      = 0.0;
218         double next_percentage = 0.0;
219         int i;
220 
221         for (i = 0 ; i < (d->sixteenBit ? 65535 : 255) ; ++i)
222         {
223             new_count       += hist->getValue(channel, i);
224             percentage      = new_count / count;
225             next_percentage = (new_count + hist->getValue(channel, i + 1)) / count;
226 
227             if (fabs(percentage - 0.006) < fabs(next_percentage - 0.006))
228             {
229                 d->levels->low_input[channel] = i + 1;
230                 break;
231             }
232         }
233 
234         //  Set the high input
235 
236         new_count = 0.0;
237 
238         for (i = (d->sixteenBit ? 65535 : 255) ; i > 0 ; --i)
239         {
240             new_count       += hist->getValue(channel, i);
241             percentage      = new_count / count;
242             next_percentage = (new_count + hist->getValue(channel, i - 1)) / count;
243 
244             if (fabs(percentage - 0.006) < fabs(next_percentage - 0.006))
245             {
246                 d->levels->high_input[channel] = i - 1;
247                 break;
248             }
249         }
250     }
251 
252     d->dirty = true;
253 }
254 
levelsInputFromColor(int channel,const DColor & color)255 int ImageLevels::levelsInputFromColor(int channel, const DColor& color)
256 {
257     switch (channel)
258     {
259         case LuminosityChannel:
260             return qMax(qMax(color.red(), color.green()), color.blue());
261 
262         case RedChannel:
263             return color.red();
264 
265         case GreenChannel:
266             return color.green();
267 
268         case BlueChannel:
269             return color.blue();
270     }
271 
272     return 0;  // just to please the compiler.
273 }
274 
levelsBlackToneAdjustByColors(int channel,const DColor & color)275 void ImageLevels::levelsBlackToneAdjustByColors(int channel, const DColor& color)
276 {
277     if (!d->levels)
278     {
279         return;
280     }
281 
282     d->levels->low_input[channel] = levelsInputFromColor(channel, color);
283     d->dirty = true;
284 }
285 
levelsWhiteToneAdjustByColors(int channel,const DColor & color)286 void ImageLevels::levelsWhiteToneAdjustByColors(int channel, const DColor& color)
287 {
288     if (!d->levels)
289     {
290         return;
291     }
292 
293     d->levels->high_input[channel] = levelsInputFromColor(channel, color);
294     d->dirty = true;
295 }
296 
levelsGrayToneAdjustByColors(int channel,const DColor & color)297 void ImageLevels::levelsGrayToneAdjustByColors(int channel, const DColor& color)
298 {
299     if (!d->levels)
300     {
301         return;
302     }
303 
304     int            input;
305     int            range;
306     double         inten;
307     double         out_light;
308     unsigned short lightness;
309 
310     // Calculate lightness value.
311 
312     lightness = (unsigned short)LEVELS_RGB_INTENSITY(color.red(), color.green(), color.blue());
313     input     = levelsInputFromColor(channel, color);
314     range     = d->levels->high_input[channel] - d->levels->low_input[channel];
315 
316     if (range <= 0)
317     {
318         return;
319     }
320 
321     input -= d->levels->low_input[channel];
322 
323     if (input < 0)
324     {
325         return;
326     }
327 
328     // Normalize input and lightness.
329 
330     inten     = (double) input     / (double) range;
331     out_light = (double) lightness / (double) range;
332 
333     if (out_light <= 0)
334     {
335         return;
336     }
337 
338     // Map selected color to corresponding lightness.
339 
340     d->levels->gamma[channel] = log(inten) / log(out_light);
341     d->dirty = true;
342 }
343 
levelsCalculateTransfers()344 void ImageLevels::levelsCalculateTransfers()
345 {
346     double inten;
347     int    i, j;
348 
349     if (!d->levels)
350     {
351         return;
352     }
353 
354     // Recalculate the levels arrays.
355 
356     for (j = 0 ; j < 5 ; ++j)
357     {
358         for (i = 0 ; i <= (d->sixteenBit ? 65535 : 255) ; ++i)
359         {
360             //  determine input intensity.
361 
362             if (d->levels->high_input[j] != d->levels->low_input[j])
363             {
364                 inten = ((double)(i - d->levels->low_input[j]) /
365                          (double)(d->levels->high_input[j] - d->levels->low_input[j]));
366             }
367             else
368             {
369                 inten = (double)(i - d->levels->low_input[j]);
370             }
371 
372             inten = CLAMP(inten, 0.0, 1.0);
373 
374             if (d->levels->gamma[j] != 0.0)
375             {
376                 inten = pow(inten, (1.0 / d->levels->gamma[j]));
377                 (void)inten; // Remove clang warnings.
378             }
379         }
380     }
381 }
382 
levelsLutFunc(int n_channels,int channel,float value)383 float ImageLevels::levelsLutFunc(int n_channels, int channel, float value)
384 {
385     double inten;
386     int    j;
387 
388     if (!d->levels)
389     {
390         return 0.0;
391     }
392 
393     if (n_channels == 1)
394     {
395         j = 0;
396     }
397     else
398     {
399         j = channel + 1;
400     }
401 
402     inten = value;
403 
404     // For color  images this runs through the loop with j = channel +1
405     // the first time and j = 0 the second time.
406     //
407     // For bw images this runs through the loop with j = 0 the first and
408     // only time.
409 
410     for ( ; j >= 0 ; j -= (channel + 1))
411     {
412         // Don't apply the overall curve to the alpha channel.
413 
414         if ((j == 0) && ((n_channels == 2) || (n_channels == 4)) && (channel == n_channels - 1))
415         {
416             return inten;
417         }
418 
419         //  Determine input intensity.
420 
421         if (d->levels->high_input[j] != d->levels->low_input[j])
422         {
423             inten = ((double)((float)(d->sixteenBit ? 65535 : 255) * inten - d->levels->low_input[j]) /
424                      (double)(d->levels->high_input[j] - d->levels->low_input[j]));
425         }
426         else
427         {
428             inten = (double)((float)(d->sixteenBit ? 65535 : 255) * inten - d->levels->low_input[j]);
429         }
430 
431         if (d->levels->gamma[j] != 0.0)
432         {
433             if (inten >= 0.0)
434             {
435                 inten =  pow(inten, (1.0 / d->levels->gamma[j]));
436             }
437             else
438             {
439                 inten = -pow(-inten, (1.0 / d->levels->gamma[j]));
440             }
441         }
442 
443         //  determine the output intensity.
444 
445         if (d->levels->high_output[j] >= d->levels->low_output[j])
446         {
447             inten = (double)(inten * (d->levels->high_output[j] -
448                                       d->levels->low_output[j]) + d->levels->low_output[j]);
449         }
450         else
451         {
452             inten = (double)(d->levels->low_output[j] - inten *
453                              (d->levels->low_output[j] - d->levels->high_output[j]));
454         }
455 
456         inten /= (float)(d->sixteenBit ? 65535 : 255);
457     }
458 
459     return inten;
460 }
461 
levelsLutSetup(int nchannels)462 void ImageLevels::levelsLutSetup(int nchannels)
463 {
464     int    i;
465     uint   v;
466     double val;
467 
468     if (d->lut->luts)
469     {
470         for (i = 0 ; i < d->lut->nchannels ; ++i)
471         {
472             delete [] d->lut->luts[i];
473         }
474 
475         delete [] d->lut->luts;
476     }
477 
478     d->lut->nchannels = nchannels;
479     d->lut->luts      = new unsigned short*[d->lut->nchannels];
480 
481     for (i = 0 ; i < d->lut->nchannels ; ++i)
482     {
483         d->lut->luts[i] = new unsigned short[(d->sixteenBit ? 65535 : 255) + 1];
484 
485         for (v = 0 ; v <= (uint)(d->sixteenBit ? 65535 : 255) ; ++v)
486         {
487             // to add gamma correction use func(v ^ g) ^ 1/g instead.
488 
489             val = (float)(d->sixteenBit ? 65535 : 255) *
490                   levelsLutFunc(d->lut->nchannels, i, v / (float)(d->sixteenBit ? 65535 : 255)) + 0.5;
491 
492             d->lut->luts[i][v] = (unsigned short)CLAMP(val, 0.0, (d->sixteenBit ? 65535.0 : 255.0));
493         }
494     }
495 }
496 
levelsLutProcess(uchar * const srcPR,uchar * const destPR,int w,int h)497 void ImageLevels::levelsLutProcess(uchar* const srcPR, uchar* const destPR, int w, int h)
498 {
499     unsigned short* lut0 = nullptr, *lut1 = nullptr, *lut2 = nullptr, *lut3 = nullptr;
500 
501     int   i;
502 
503     if (d->lut->nchannels > 0)
504     {
505         lut0 = d->lut->luts[0];
506     }
507 
508     if (d->lut->nchannels > 1)
509     {
510         lut1 = d->lut->luts[1];
511     }
512 
513     if (d->lut->nchannels > 2)
514     {
515         lut2 = d->lut->luts[2];
516     }
517 
518     if (d->lut->nchannels > 3)
519     {
520         lut3 = d->lut->luts[3];
521     }
522 
523     if (!d->sixteenBit)        // 8 bits image.
524     {
525         uchar red, green, blue, alpha;
526         uchar* ptr = srcPR;
527         uchar* dst = destPR;
528 
529         for (i = 0 ; i < w * h ; ++i)
530         {
531             blue  = ptr[0];
532             green = ptr[1];
533             red   = ptr[2];
534             alpha = ptr[3];
535 
536             if (d->lut->nchannels > 0)
537             {
538                 red = lut0[red];
539             }
540 
541             if (d->lut->nchannels > 1)
542             {
543                 green = lut1[green];
544             }
545 
546             if (d->lut->nchannels > 2)
547             {
548                 blue = lut2[blue];
549             }
550 
551             if (d->lut->nchannels > 3)
552             {
553                 alpha = lut3[alpha];
554             }
555 
556             dst[0] = blue;
557             dst[1] = green;
558             dst[2] = red;
559             dst[3] = alpha;
560 
561             ptr   += 4;
562             dst   += 4;
563         }
564     }
565     else               // 16 bits image.
566     {
567         unsigned short red, green, blue, alpha;
568         unsigned short* ptr = reinterpret_cast<unsigned short*>(srcPR);
569         unsigned short* dst = reinterpret_cast<unsigned short*>(destPR);
570 
571         for (i = 0 ; i < w * h ; ++i)
572         {
573             blue  = ptr[0];
574             green = ptr[1];
575             red   = ptr[2];
576             alpha = ptr[3];
577 
578             if (d->lut->nchannels > 0)
579             {
580                 red = lut0[red];
581             }
582 
583             if (d->lut->nchannels > 1)
584             {
585                 green = lut1[green];
586             }
587 
588             if (d->lut->nchannels > 2)
589             {
590                 blue = lut2[blue];
591             }
592 
593             if (d->lut->nchannels > 3)
594             {
595                 alpha = lut3[alpha];
596             }
597 
598             dst[0] = blue;
599             dst[1] = green;
600             dst[2] = red;
601             dst[3] = alpha;
602 
603             ptr   += 4;
604             dst   += 4;
605         }
606     }
607 }
608 
setLevelGammaValue(int channel,double val)609 void ImageLevels::setLevelGammaValue(int channel, double val)
610 {
611     if (d->levels && (channel >= 0) && (channel < 5))
612     {
613         d->levels->gamma[channel] = val;
614         d->dirty = true;
615     }
616 }
617 
setLevelLowInputValue(int channel,int val)618 void ImageLevels::setLevelLowInputValue(int channel, int val)
619 {
620     if (d->levels && (channel >= 0) && (channel < 5))
621     {
622         d->levels->low_input[channel] = val;
623         d->dirty = true;
624     }
625 }
626 
setLevelHighInputValue(int channel,int val)627 void ImageLevels::setLevelHighInputValue(int channel, int val)
628 {
629     if (d->levels && (channel >= 0) && (channel < 5))
630     {
631         d->levels->high_input[channel] = val;
632         d->dirty = true;
633     }
634 }
635 
setLevelLowOutputValue(int channel,int val)636 void ImageLevels::setLevelLowOutputValue(int channel, int val)
637 {
638     if (d->levels && (channel >= 0) && (channel < 5))
639     {
640         d->levels->low_output[channel] = val;
641         d->dirty = true;
642     }
643 }
644 
setLevelHighOutputValue(int channel,int val)645 void ImageLevels::setLevelHighOutputValue(int channel, int val)
646 {
647     if (d->levels && (channel >= 0) && (channel < 5))
648     {
649         d->levels->high_output[channel] = val;
650         d->dirty = true;
651     }
652 }
653 
getLevelGammaValue(int channel)654 double ImageLevels::getLevelGammaValue(int channel)
655 {
656     if (d->levels && (channel >= 0) && (channel < 5))
657     {
658         return (d->levels->gamma[channel]);
659     }
660 
661     return 0.0;
662 }
663 
getLevelLowInputValue(int channel)664 int ImageLevels::getLevelLowInputValue(int channel)
665 {
666     if (d->levels && (channel >= 0) && (channel < 5))
667     {
668         return (d->levels->low_input[channel]);
669     }
670 
671     return 0;
672 }
673 
getLevelHighInputValue(int channel)674 int ImageLevels::getLevelHighInputValue(int channel)
675 {
676     if (d->levels && (channel >= 0) && (channel < 5))
677     {
678         return (d->levels->high_input[channel]);
679     }
680 
681     return 0;
682 }
683 
getLevelLowOutputValue(int channel)684 int ImageLevels::getLevelLowOutputValue(int channel)
685 {
686     if (d->levels && (channel >= 0) && (channel < 5))
687     {
688         return (d->levels->low_output[channel]);
689     }
690 
691     return 0;
692 }
693 
getLevelHighOutputValue(int channel)694 int ImageLevels::getLevelHighOutputValue(int channel)
695 {
696     if (d->levels && (channel >= 0) && (channel < 5))
697     {
698         return (d->levels->high_output[channel]);
699     }
700 
701     return 0;
702 }
703 
loadLevelsFromGimpLevelsFile(const QUrl & fileUrl)704 bool ImageLevels::loadLevelsFromGimpLevelsFile(const QUrl& fileUrl)
705 {
706     // TODO : support QUrl !
707 
708     FILE*   file = nullptr;
709     int     low_input[5];
710     int     high_input[5];
711     int     low_output[5];
712     int     high_output[5];
713     double  gamma[5];
714     int     i, fields;
715     char    buf[50];
716     char*   nptr = nullptr;
717 
718 #ifdef Q_OS_WIN
719 
720     file = _wfopen((const wchar_t*)fileUrl.toLocalFile().utf16(), L"r");
721 
722 #else
723 
724     file = fopen(fileUrl.toLocalFile().toUtf8().constData(), "r");
725 
726 #endif
727 
728     if (!file)
729     {
730         return false;
731     }
732 
733     if (! fgets(buf, sizeof(buf), file))
734     {
735         fclose(file);
736         return false;
737     }
738 
739     if (strcmp(buf, "# GIMP Levels File\n") != 0)
740     {
741         fclose(file);
742         return false;
743     }
744 
745     for (i = 0 ; i < 5 ; ++i)
746     {
747         // FIXME: scanf without field width limits can crash with huge input data
748 
749         fields = fscanf(file, "%d %d %d %d ",
750                         &low_input[i],
751                         &high_input[i],
752                         &low_output[i],
753                         &high_output[i]);
754 
755         if (fields != 4)
756         {
757             qCWarning(DIGIKAM_DIMG_LOG) <<  "Invalid Gimp levels file!";
758             fclose(file);
759             return false;
760         }
761 
762         if (!fgets(buf, 50, file))
763         {
764             qCWarning(DIGIKAM_DIMG_LOG) <<  "Invalid Gimp levels file!";
765             fclose(file);
766             return false;
767         }
768 
769         gamma[i] = strtod(buf, &nptr);
770 
771         if (buf == nptr || errno == ERANGE)
772         {
773             qCWarning(DIGIKAM_DIMG_LOG) <<  "Invalid Gimp levels file!";
774             fclose(file);
775             return false;
776         }
777     }
778 
779     for (i = 0 ; i < 5 ; ++i)
780     {
781         setLevelGammaValue(i, gamma[i]);
782         setLevelLowInputValue(i,   d->sixteenBit ? low_input[i]   * 255 : low_input[i]);
783         setLevelHighInputValue(i,  d->sixteenBit ? high_input[i]  * 255 : high_input[i]);
784         setLevelLowOutputValue(i,  d->sixteenBit ? low_output[i]  * 255 : low_output[i]);
785         setLevelHighOutputValue(i, d->sixteenBit ? high_output[i] * 255 : high_output[i]);
786     }
787 
788     fclose(file);
789     return true;
790 }
791 
saveLevelsToGimpLevelsFile(const QUrl & fileUrl)792 bool ImageLevels::saveLevelsToGimpLevelsFile(const QUrl& fileUrl)
793 {
794     // TODO : support QUrl !
795 
796     FILE* file = nullptr;
797     int   i;
798 
799 #ifdef Q_OS_WIN
800 
801     file = _wfopen((const wchar_t*)fileUrl.toLocalFile().utf16(), L"w");
802 
803 #else
804 
805     file = fopen(fileUrl.toLocalFile().toUtf8().constData(), "w");
806 
807 #endif
808 
809     if (!file)
810     {
811         return false;
812     }
813 
814     fprintf(file, "# GIMP Levels File\n");
815 
816     for (i = 0 ; i < 5 ; ++i)
817     {
818         char buf[256];
819         sprintf(buf, "%f", getLevelGammaValue(i));
820 
821         fprintf(file, "%d %d %d %d %s\n",
822                 d->sixteenBit ? getLevelLowInputValue(i)  / 255 : getLevelLowInputValue(i),
823                 d->sixteenBit ? getLevelHighInputValue(i) / 255 : getLevelHighInputValue(i),
824                 d->sixteenBit ? getLevelLowOutputValue(i) / 255 : getLevelLowOutputValue(i),
825                 d->sixteenBit ? getLevelHighInputValue(i) / 255 : getLevelHighInputValue(i),
826                 buf);
827     }
828 
829     fflush(file);
830     fclose(file);
831 
832     return true;
833 }
834 
835 } // namespace Digikam
836