1
/* The GIMP -- an image manipulation program
2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
#include <glib-object.h>
23
#include "libgimpmath/gimpmath.h"
25
#include "paint-types.h"
27
#include "base/gimplut.h"
28
#include "base/pixel-region.h"
29
#include "base/temp-buf.h"
31
#include "paint-funcs/paint-funcs.h"
33
#include "core/gimp.h"
34
#include "core/gimpdrawable.h"
35
#include "core/gimpimage.h"
37
#include "gimpdodgeburn.h"
38
#include "gimpdodgeburnoptions.h"
40
#include "gimp-intl.h"
43
static void gimp_dodge_burn_class_init (GimpDodgeBurnClass *klass);
44
static void gimp_dodge_burn_init (GimpDodgeBurn *dodgeburn);
46
static void gimp_dodge_burn_finalize (GObject *object);
48
static void gimp_dodge_burn_paint (GimpPaintCore *paint_core,
49
GimpDrawable *drawable,
50
GimpPaintOptions *paint_options,
51
GimpPaintState paint_state,
53
static void gimp_dodge_burn_motion (GimpPaintCore *paint_core,
54
GimpDrawable *drawable,
55
GimpPaintOptions *paint_options);
57
static void gimp_dodge_burn_make_luts (GimpDodgeBurn *dodgeburn,
59
GimpDodgeBurnType type,
60
GimpTransferMode mode,
61
GimpDrawable *drawable);
63
static gfloat gimp_dodge_burn_highlights_lut_func (gpointer user_data,
67
static gfloat gimp_dodge_burn_midtones_lut_func (gpointer user_data,
71
static gfloat gimp_dodge_burn_shadows_lut_func (gpointer user_data,
77
static GimpBrushCoreClass *parent_class = NULL;
81
gimp_dodge_burn_register (Gimp *gimp,
82
GimpPaintRegisterCallback callback)
86
GIMP_TYPE_DODGE_BURN_OPTIONS,
91
gimp_dodge_burn_get_type (void)
93
static GType type = 0;
97
static const GTypeInfo info =
99
sizeof (GimpDodgeBurnClass),
100
(GBaseInitFunc) NULL,
101
(GBaseFinalizeFunc) NULL,
102
(GClassInitFunc) gimp_dodge_burn_class_init,
103
NULL, /* class_finalize */
104
NULL, /* class_data */
105
sizeof (GimpDodgeBurn),
107
(GInstanceInitFunc) gimp_dodge_burn_init,
110
type = g_type_register_static (GIMP_TYPE_BRUSH_CORE,
119
gimp_dodge_burn_class_init (GimpDodgeBurnClass *klass)
121
GObjectClass *object_class = G_OBJECT_CLASS (klass);
122
GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
123
GimpBrushCoreClass *brush_core_class = GIMP_BRUSH_CORE_CLASS (klass);
125
parent_class = g_type_class_peek_parent (klass);
127
object_class->finalize = gimp_dodge_burn_finalize;
129
paint_core_class->paint = gimp_dodge_burn_paint;
131
brush_core_class->handles_changing_brush = TRUE;
135
gimp_dodge_burn_init (GimpDodgeBurn *dodgeburn)
140
gimp_dodge_burn_finalize (GObject *object)
142
GimpDodgeBurn *dodgeburn = GIMP_DODGE_BURN (object);
146
gimp_lut_free (dodgeburn->lut);
147
dodgeburn->lut = NULL;
150
G_OBJECT_CLASS (parent_class)->finalize (object);
154
gimp_dodge_burn_paint (GimpPaintCore *paint_core,
155
GimpDrawable *drawable,
156
GimpPaintOptions *paint_options,
157
GimpPaintState paint_state,
160
GimpDodgeBurn *dodgeburn = GIMP_DODGE_BURN (paint_core);
161
GimpDodgeBurnOptions *options = GIMP_DODGE_BURN_OPTIONS (paint_options);
165
case GIMP_PAINT_STATE_INIT:
166
dodgeburn->lut = gimp_lut_new ();
168
gimp_dodge_burn_make_luts (dodgeburn,
175
case GIMP_PAINT_STATE_MOTION:
176
gimp_dodge_burn_motion (paint_core, drawable, paint_options);
179
case GIMP_PAINT_STATE_FINISH:
182
gimp_lut_free (dodgeburn->lut);
183
dodgeburn->lut = NULL;
190
gimp_dodge_burn_motion (GimpPaintCore *paint_core,
191
GimpDrawable *drawable,
192
GimpPaintOptions *paint_options)
194
GimpDodgeBurn *dodgeburn = GIMP_DODGE_BURN (paint_core);
195
GimpContext *context = GIMP_CONTEXT (paint_options);
196
GimpPressureOptions *pressure_options = paint_options->pressure_options;
200
PixelRegion srcPR, destPR, tempPR;
204
gimage = gimp_item_get_image (GIMP_ITEM (drawable));
206
if (gimp_drawable_is_indexed (drawable))
209
opacity = gimp_paint_options_get_fade (paint_options, gimage,
210
paint_core->pixel_dist);
214
area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options);
218
/* Constant painting --get a copy of the orig drawable (with no
219
* paint from this stroke yet)
222
GimpItem *item = GIMP_ITEM (drawable);
225
x1 = CLAMP (area->x, 0, gimp_item_width (item));
226
y1 = CLAMP (area->y, 0, gimp_item_height (item));
227
x2 = CLAMP (area->x + area->width, 0, gimp_item_width (item));
228
y2 = CLAMP (area->y + area->height, 0, gimp_item_height (item));
230
if (!(x2 - x1) || !(y2 - y1))
233
/* get the original untouched image */
234
orig = gimp_paint_core_get_orig_image (paint_core, drawable, x1, y1, x2, y2);
236
srcPR.bytes = orig->bytes;
241
srcPR.rowstride = srcPR.bytes * orig->width;
242
srcPR.data = temp_buf_data (orig);
245
/* tempPR will hold the dodgeburned region */
246
tempPR.bytes = srcPR.bytes;
251
tempPR.rowstride = tempPR.bytes * tempPR.w;
252
tempPR.data = g_malloc (tempPR.h * tempPR.rowstride);
254
temp_data = tempPR.data;
256
/* DodgeBurn the region */
257
gimp_lut_process (dodgeburn->lut, &srcPR, &tempPR);
259
/* The dest is the paint area we got above (= canvas_buf) */
260
destPR.bytes = area->bytes;
263
destPR.w = area->width;
264
destPR.h = area->height;
265
destPR.rowstride = area->width * destPR.bytes;
266
destPR.data = temp_buf_data (area);
268
/* Now add an alpha to the dodgeburned region
269
* and put this in area = canvas_buf
271
if (! gimp_drawable_has_alpha (drawable))
272
add_alpha_region (&tempPR, &destPR);
274
copy_region (&tempPR, &destPR);
276
if (pressure_options->opacity)
277
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
279
/* Replace the newly dodgedburned area (canvas_buf) to the gimage */
280
gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core), drawable,
281
MIN (opacity, GIMP_OPACITY_OPAQUE),
282
gimp_context_get_opacity (context),
283
gimp_paint_options_get_brush_mode (paint_options),
284
GIMP_PAINT_CONSTANT);
290
gimp_dodge_burn_make_luts (GimpDodgeBurn *dodgeburn,
292
GimpDodgeBurnType type,
293
GimpTransferMode mode,
294
GimpDrawable *drawable)
296
GimpLutFunc lut_func;
297
gint nchannels = gimp_drawable_bytes (drawable);
298
static gfloat exposure;
300
exposure = db_exposure / 100.0;
302
/* make the exposure negative if burn for luts*/
303
if (type == GIMP_BURN)
304
exposure = -exposure;
308
case GIMP_HIGHLIGHTS:
309
lut_func = gimp_dodge_burn_highlights_lut_func;
312
lut_func = gimp_dodge_burn_midtones_lut_func;
315
lut_func = gimp_dodge_burn_shadows_lut_func;
322
gimp_lut_setup_exact (dodgeburn->lut,
323
lut_func, (gpointer) &exposure,
328
gimp_dodge_burn_highlights_lut_func (gpointer user_data,
333
gfloat *exposure_ptr = (gfloat *) user_data;
334
gfloat exposure = *exposure_ptr;
335
gfloat factor = 1.0 + exposure * (.333333);
337
if ((nchannels == 2 && channel == 1) ||
338
(nchannels == 4 && channel == 3))
341
return factor * value;
345
gimp_dodge_burn_midtones_lut_func (gpointer user_data,
350
gfloat *exposure_ptr = (gfloat *) user_data;
351
gfloat exposure = *exposure_ptr;
354
if ((nchannels == 2 && channel == 1) ||
355
(nchannels == 4 && channel == 3))
359
factor = 1.0 - exposure * (.333333);
361
factor = 1 / (1.0 + exposure);
363
return pow (value, factor);
367
gimp_dodge_burn_shadows_lut_func (gpointer user_data,
372
gfloat *exposure_ptr = (gfloat *) user_data;
373
gfloat exposure = *exposure_ptr;
377
if ((nchannels == 2 && channel == 1) ||
378
(nchannels == 4 && channel == 3))
383
factor = 0.333333 * exposure;
384
new_value = factor + value - factor * value;
386
else /* exposure < 0 */
388
factor = -0.333333 * exposure;
391
else /*factor <= value <=1*/
392
new_value = (value - factor)/(1 - factor);