1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpbrightnesscontrastconfig.c
5  * Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24 #include <gegl.h>
25 
26 #include "libgimpmath/gimpmath.h"
27 #include "libgimpconfig/gimpconfig.h"
28 
29 #include "operations-types.h"
30 
31 #include "gimpbrightnesscontrastconfig.h"
32 #include "gimplevelsconfig.h"
33 
34 #include "gimp-intl.h"
35 
36 
37 enum
38 {
39   PROP_0,
40   PROP_BRIGHTNESS,
41   PROP_CONTRAST
42 };
43 
44 
45 static void     gimp_brightness_contrast_config_iface_init   (GimpConfigInterface *iface);
46 
47 static void     gimp_brightness_contrast_config_get_property (GObject      *object,
48                                                               guint         property_id,
49                                                               GValue       *value,
50                                                               GParamSpec   *pspec);
51 static void     gimp_brightness_contrast_config_set_property (GObject      *object,
52                                                               guint         property_id,
53                                                               const GValue *value,
54                                                               GParamSpec   *pspec);
55 
56 static gboolean gimp_brightness_contrast_config_equal        (GimpConfig   *a,
57                                                               GimpConfig   *b);
58 
59 
G_DEFINE_TYPE_WITH_CODE(GimpBrightnessContrastConfig,gimp_brightness_contrast_config,GIMP_TYPE_OPERATION_SETTINGS,G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,gimp_brightness_contrast_config_iface_init))60 G_DEFINE_TYPE_WITH_CODE (GimpBrightnessContrastConfig,
61                          gimp_brightness_contrast_config,
62                          GIMP_TYPE_OPERATION_SETTINGS,
63                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,
64                                                 gimp_brightness_contrast_config_iface_init))
65 
66 #define parent_class gimp_brightness_contrast_config_parent_class
67 
68 
69 static void
70 gimp_brightness_contrast_config_class_init (GimpBrightnessContrastConfigClass *klass)
71 {
72   GObjectClass      *object_class   = G_OBJECT_CLASS (klass);
73   GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
74 
75   object_class->set_property        = gimp_brightness_contrast_config_set_property;
76   object_class->get_property        = gimp_brightness_contrast_config_get_property;
77 
78   viewable_class->default_icon_name = "gimp-tool-brightness-contrast";
79 
80   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_BRIGHTNESS,
81                            "brightness",
82                            _("Brightness"),
83                            _("Brightness"),
84                            -1.0, 1.0, 0.0, 0);
85 
86   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_CONTRAST,
87                            "contrast",
88                            _("Contrast"),
89                            _("Contrast"),
90                            -1.0, 1.0, 0.0, 0);
91 }
92 
93 static void
gimp_brightness_contrast_config_iface_init(GimpConfigInterface * iface)94 gimp_brightness_contrast_config_iface_init (GimpConfigInterface *iface)
95 {
96   iface->equal = gimp_brightness_contrast_config_equal;
97 }
98 
99 static void
gimp_brightness_contrast_config_init(GimpBrightnessContrastConfig * self)100 gimp_brightness_contrast_config_init (GimpBrightnessContrastConfig *self)
101 {
102 }
103 
104 static void
gimp_brightness_contrast_config_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)105 gimp_brightness_contrast_config_get_property (GObject    *object,
106                                               guint       property_id,
107                                               GValue     *value,
108                                               GParamSpec *pspec)
109 {
110   GimpBrightnessContrastConfig *self = GIMP_BRIGHTNESS_CONTRAST_CONFIG (object);
111 
112   switch (property_id)
113     {
114     case PROP_BRIGHTNESS:
115       g_value_set_double (value, self->brightness);
116       break;
117 
118     case PROP_CONTRAST:
119       g_value_set_double (value, self->contrast);
120       break;
121 
122     default:
123       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
124       break;
125     }
126 }
127 
128 static void
gimp_brightness_contrast_config_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)129 gimp_brightness_contrast_config_set_property (GObject      *object,
130                                               guint         property_id,
131                                               const GValue *value,
132                                               GParamSpec   *pspec)
133 {
134   GimpBrightnessContrastConfig *self = GIMP_BRIGHTNESS_CONTRAST_CONFIG (object);
135 
136   switch (property_id)
137     {
138     case PROP_BRIGHTNESS:
139       self->brightness = g_value_get_double (value);
140       break;
141 
142     case PROP_CONTRAST:
143       self->contrast = g_value_get_double (value);
144       break;
145 
146    default:
147       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
148       break;
149     }
150 }
151 
152 static gboolean
gimp_brightness_contrast_config_equal(GimpConfig * a,GimpConfig * b)153 gimp_brightness_contrast_config_equal (GimpConfig *a,
154                                        GimpConfig *b)
155 {
156   GimpBrightnessContrastConfig *config_a = GIMP_BRIGHTNESS_CONTRAST_CONFIG (a);
157   GimpBrightnessContrastConfig *config_b = GIMP_BRIGHTNESS_CONTRAST_CONFIG (b);
158 
159   if (! gimp_operation_settings_config_equal_base (a, b) ||
160       config_a->brightness != config_b->brightness       ||
161       config_a->contrast   != config_b->contrast)
162     {
163       return FALSE;
164     }
165 
166   return TRUE;
167 }
168 
169 
170 /*  public functions  */
171 
172 GimpLevelsConfig *
gimp_brightness_contrast_config_to_levels_config(GimpBrightnessContrastConfig * config)173 gimp_brightness_contrast_config_to_levels_config (GimpBrightnessContrastConfig *config)
174 {
175   GimpLevelsConfig *levels;
176   gdouble           brightness;
177   gdouble           slant;
178   gdouble           value;
179 
180   g_return_val_if_fail (GIMP_IS_BRIGHTNESS_CONTRAST_CONFIG (config), NULL);
181 
182   levels = g_object_new (GIMP_TYPE_LEVELS_CONFIG, NULL);
183 
184   gimp_operation_settings_config_copy_base (GIMP_CONFIG (config),
185                                             GIMP_CONFIG (levels),
186                                             0);
187 
188   brightness = config->brightness / 2.0;
189   slant = tan ((config->contrast + 1) * G_PI_4);
190 
191   if (config->brightness >= 0)
192     {
193       value = -0.5 * slant + brightness * slant + 0.5;
194 
195       if (value < 0.0)
196         {
197           value = 0.0;
198 
199           /* this slightly convoluted math follows by inverting the
200            * calculation of the brightness/contrast LUT in base/lut-funcs.h */
201 
202           levels->low_input[GIMP_HISTOGRAM_VALUE] =
203             (- brightness * slant + 0.5 * slant - 0.5) / (slant - brightness * slant);
204         }
205 
206       levels->low_output[GIMP_HISTOGRAM_VALUE] = value;
207 
208       value = 0.5 * slant + 0.5;
209 
210       if (value > 1.0)
211         {
212           value = 1.0;
213 
214           levels->high_input[GIMP_HISTOGRAM_VALUE] =
215             (- brightness * slant + 0.5 * slant + 0.5) / (slant - brightness * slant);
216         }
217 
218       levels->high_output[GIMP_HISTOGRAM_VALUE] = value;
219     }
220   else
221     {
222       value = 0.5 - 0.5 * slant;
223 
224       if (value < 0.0)
225         {
226           value = 0.0;
227 
228           levels->low_input[GIMP_HISTOGRAM_VALUE] =
229             (0.5 * slant - 0.5) / (slant + brightness * slant);
230         }
231 
232       levels->low_output[GIMP_HISTOGRAM_VALUE] = value;
233 
234       value = slant * brightness + slant * 0.5 + 0.5;
235 
236       if (value > 1.0)
237         {
238           value = 1.0;
239 
240           levels->high_input[GIMP_HISTOGRAM_VALUE] =
241             (0.5 * slant + 0.5) / (slant + brightness * slant);
242         }
243 
244       levels->high_output[GIMP_HISTOGRAM_VALUE] = value;
245     }
246 
247   return levels;
248 }
249