Bug 622054 - Levels Tool gray point picker causes lockup

Bail out in gimp_levels_config_adjust_by_colors() if pure
back or white was picked as gray (gamma).
This commit is contained in:
Michael Natterer 2013-03-27 22:28:29 +01:00
parent 71c88aebdc
commit c865d8f141
2 changed files with 52 additions and 5 deletions

View File

@ -562,24 +562,35 @@ gimp_levels_config_adjust_by_colors (GimpLevelsConfig *config,
range = config->high_input[channel] - config->low_input[channel]; range = config->high_input[channel] - config->low_input[channel];
if (range <= 0) if (range <= 0)
return; goto out;
input -= config->low_input[channel]; input -= config->low_input[channel];
if (input < 0) if (input < 0)
return; goto out;
/* Normalize input and lightness */ /* Normalize input and lightness */
inten = input / range; inten = input / range;
out_light = lightness/ range; out_light = lightness / range;
if (out_light <= 0) /* See bug 622054: picking pure black or white as gamma doesn't
return; * work. But we cannot compare to 0.0 or 1.0 because cpus and
* compilers are shit. If you try to check out_light using
* printf() it will give exact 0.0 or 1.0 anyway, probably
* because the generated code is different and out_light doesn't
* live in a register. That must be why the cpu/compiler mafia
* invented epsilon and defined this shit to be the programmer's
* responsibility.
*/
if (out_light <= 0.0001 || out_light >= 0.9999)
goto out;
/* Map selected color to corresponding lightness */ /* Map selected color to corresponding lightness */
config->gamma[channel] = log (inten) / log (out_light); config->gamma[channel] = log (inten) / log (out_light);
config->gamma[channel] = CLAMP (config->gamma[channel], 0.1, 10.0);
g_object_notify (G_OBJECT (config), "gamma"); g_object_notify (G_OBJECT (config), "gamma");
} }
out:
g_object_thaw_notify (G_OBJECT (config)); g_object_thaw_notify (G_OBJECT (config));
} }

View File

@ -27,6 +27,8 @@
#include "core/gimpimage.h" #include "core/gimpimage.h"
#include "core/gimplayer.h" #include "core/gimplayer.h"
#include "operations/gimplevelsconfig.h"
#include "tests.h" #include "tests.h"
#include "gimp-app-test-utils.h" #include "gimp-app-test-utils.h"
@ -222,6 +224,39 @@ remove_layer (GimpTestFixture *fixture,
g_assert_cmpint (gimp_image_get_n_layers (image), ==, 0); g_assert_cmpint (gimp_image_get_n_layers (image), ==, 0);
} }
/**
* white_graypoint_in_red_levels:
* @fixture:
* @data:
*
* Makes sure the levels algorithm can handle when the graypoint is
* white. It's easy to get a divide by zero problem when trying to
* calculate what gamma will give a white graypoint.
**/
static void
white_graypoint_in_red_levels (GimpTestFixture *fixture,
gconstpointer data)
{
GimpRGB black = { 0, 0, 0, 0 };
GimpRGB gray = { 1, 1, 1, 1 };
GimpRGB white = { 1, 1, 1, 1 };
GimpHistogramChannel channel = GIMP_HISTOGRAM_RED;
GimpLevelsConfig *config;
config = g_object_new (GIMP_TYPE_LEVELS_CONFIG, NULL);
gimp_levels_config_adjust_by_colors (config,
channel,
&black,
&gray,
&white);
/* Make sure we didn't end up with an invalid gamma value */
g_object_set (config,
"gamma", config->gamma[channel],
NULL);
}
int int
main (int argc, main (int argc,
char **argv) char **argv)
@ -242,6 +277,7 @@ main (int argc,
ADD_IMAGE_TEST (add_layer); ADD_IMAGE_TEST (add_layer);
ADD_IMAGE_TEST (remove_layer); ADD_IMAGE_TEST (remove_layer);
ADD_IMAGE_TEST (rotate_non_overlapping); ADD_IMAGE_TEST (rotate_non_overlapping);
ADD_TEST (white_graypoint_in_red_levels);
/* Run the tests */ /* Run the tests */
result = g_test_run (); result = g_test_run ();