home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / dodgeburn.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  17.0 KB  |  636 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  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.
  8.  *
  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.
  13.  *
  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.
  17.  */
  18. #include "config.h"
  19.  
  20. #include <gtk/gtk.h>
  21. #include <gdk/gdkkeysyms.h>
  22.  
  23. #include "apptypes.h"
  24.  
  25. #include "appenv.h"
  26. #include "drawable.h"
  27. #include "dodgeburn.h"
  28. #include "gdisplay.h"
  29. #include "gimplut.h"
  30. #include "gimpui.h"
  31. #include "paint_funcs.h"
  32. #include "paint_core.h"
  33. #include "paint_options.h"
  34. #include "selection.h"
  35. #include "tools.h"
  36. #include "gimage.h"
  37.  
  38. #include "libgimp/gimpmath.h"
  39.  
  40. #include "libgimp/gimpintl.h"
  41.  
  42.  
  43. /*  the dodgeburn structures  */
  44.  
  45. typedef struct _DodgeBurnOptions DodgeBurnOptions;
  46.  
  47. struct _DodgeBurnOptions
  48. {
  49.   PaintOptions   paint_options;
  50.  
  51.   DodgeBurnType  type;
  52.   DodgeBurnType  type_d;
  53.   GtkWidget     *type_w[2];
  54.  
  55.   DodgeBurnMode  mode;     /*highlights, midtones, shadows*/
  56.   DodgeBurnMode  mode_d;
  57.   GtkWidget     *mode_w[3];
  58.  
  59.   gdouble        exposure;
  60.   gdouble        exposure_d;
  61.   GtkObject     *exposure_w;
  62.  
  63.   GimpLut       *lut;
  64. };
  65.  
  66. static void 
  67. dodgeburn_make_luts (PaintCore *, double, DodgeBurnType, DodgeBurnMode, 
  68.              GimpLut *, GimpDrawable *);
  69.  
  70. static gfloat dodgeburn_highlights_lut_func (void *, int, int, gfloat);
  71. static gfloat dodgeburn_midtones_lut_func   (void *, int, int, gfloat);
  72. static gfloat dodgeburn_shadows_lut_func    (void *, int, int, gfloat);
  73.  
  74. /* The dodge burn lookup tables */
  75. gfloat dodgeburn_highlights (void *, int, int, gfloat);
  76. gfloat dodgeburn_midtones   (void *, int, int, gfloat);
  77. gfloat dodgeburn_shadows    (void *, int, int, gfloat);
  78.  
  79. /*  the dodgeburn tool options  */
  80. static DodgeBurnOptions * dodgeburn_options = NULL;
  81.  
  82. /* Non gui function */
  83. static double  non_gui_exposure;
  84. static GimpLut *non_gui_lut;
  85.  
  86. /* Default values */
  87. #define DODGEBURN_DEFAULT_TYPE     DODGE
  88. #define DODGEBURN_DEFAULT_EXPOSURE 50.0
  89. #define DODGEBURN_DEFAULT_MODE     DODGEBURN_HIGHLIGHTS
  90.  
  91. static void         dodgeburn_motion     (PaintCore *, 
  92.                      PaintPressureOptions *,
  93.                      double, GimpLut *, GimpDrawable *);
  94. static void         dodgeburn_init       (PaintCore *, GimpDrawable *);
  95. static void         dodgeburn_finish    (PaintCore *, GimpDrawable *);
  96.  
  97. /* functions  */
  98.  
  99. static void
  100. dodgeburn_options_reset (void)
  101. {
  102.   DodgeBurnOptions *options = dodgeburn_options;
  103.  
  104.   paint_options_reset ((PaintOptions *) options);
  105.  
  106.   gtk_adjustment_set_value (GTK_ADJUSTMENT (options->exposure_w),
  107.                 options->exposure_d);
  108.  
  109.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->type_w[options->type_d]), TRUE);
  110.  
  111.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->mode_w[options->mode_d]), TRUE);
  112. }
  113.  
  114. static DodgeBurnOptions *
  115. dodgeburn_options_new (void)
  116. {
  117.   DodgeBurnOptions *options;
  118.  
  119.   GtkWidget *vbox;
  120.   GtkWidget *hbox;
  121.   GtkWidget *label;
  122.   GtkWidget *scale;
  123.   GtkWidget *frame;
  124.  
  125.   /*  the new dodgeburn tool options structure  */
  126.   options = g_new (DodgeBurnOptions, 1);
  127.   paint_options_init ((PaintOptions *) options,
  128.               DODGEBURN,
  129.               dodgeburn_options_reset);
  130.  
  131.   options->type     = options->type_d     = DODGEBURN_DEFAULT_TYPE;
  132.   options->exposure = options->exposure_d = DODGEBURN_DEFAULT_EXPOSURE;
  133.   options->mode     = options->mode_d     = DODGEBURN_DEFAULT_MODE;
  134.  
  135.   /*  the main vbox  */
  136.   vbox = ((ToolOptions *) options)->main_vbox;
  137.  
  138.   /*  the exposure scale  */
  139.   hbox = gtk_hbox_new (FALSE, 4);
  140.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  141.  
  142.   label = gtk_label_new (_("Exposure:"));
  143.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
  144.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  145.   gtk_widget_show (label);
  146.  
  147.   options->exposure_w =
  148.     gtk_adjustment_new (options->exposure_d, 0.0, 100.0, 1.0, 1.0, 0.0);
  149.   scale = gtk_hscale_new (GTK_ADJUSTMENT (options->exposure_w));
  150.   gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
  151.   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  152.   gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
  153.  
  154.   gtk_signal_connect (GTK_OBJECT (options->exposure_w), "value_changed",
  155.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  156.               &options->exposure);
  157.  
  158.   gtk_widget_show (scale);
  159.   gtk_widget_show (hbox);
  160.  
  161.   /* the type (dodge or burn) */
  162.   frame = gimp_radio_group_new2 (TRUE, _("Type"),
  163.                  gimp_radio_button_update,
  164.                  &options->type, (gpointer) options->type,
  165.  
  166.                  _("Dodge"), (gpointer) DODGE,
  167.                  &options->type_w[0],
  168.                  _("Burn"), (gpointer) BURN,
  169.                  &options->type_w[1],
  170.  
  171.                  NULL);
  172.  
  173.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  174.   gtk_widget_show (frame);
  175.  
  176.   /*  mode (highlights, midtones, or shadows)  */
  177.   frame =
  178.     gimp_radio_group_new2 (TRUE, _("Mode"),
  179.                gimp_radio_button_update,
  180.                &options->mode, (gpointer) options->mode,
  181.  
  182.                _("Highlights"), (gpointer) DODGEBURN_HIGHLIGHTS, 
  183.                &options->mode_w[0],
  184.                _("Midtones"), (gpointer) DODGEBURN_MIDTONES,
  185.                &options->mode_w[1],
  186.                _("Shadows"), (gpointer) DODGEBURN_SHADOWS,
  187.                &options->mode_w[2],
  188.  
  189.                NULL);
  190.  
  191.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  192.   gtk_widget_show (frame);
  193.  
  194.   return options;
  195. }
  196.  
  197. void *
  198. dodgeburn_paint_func (PaintCore    *paint_core,
  199.              GimpDrawable *drawable,
  200.              int           state)
  201. {
  202.   switch (state)
  203.     {
  204.     case INIT_PAINT:
  205.       dodgeburn_init (paint_core, drawable);
  206.       break;
  207.     case MOTION_PAINT:
  208.       dodgeburn_motion (paint_core, 
  209.             dodgeburn_options->paint_options.pressure_options,
  210.             dodgeburn_options->exposure, dodgeburn_options->lut, drawable);
  211.       break;
  212.     case FINISH_PAINT:
  213.       dodgeburn_finish (paint_core, drawable);
  214.       break;
  215.     }
  216.  
  217.   return NULL;
  218. }
  219.  
  220. static void
  221. dodgeburn_finish (PaintCore    *paint_core,
  222.           GimpDrawable *drawable)
  223. {
  224.   /* Here we destroy the luts to do the painting with.*/
  225.   if (dodgeburn_options->lut)
  226.   {
  227.     gimp_lut_free (dodgeburn_options->lut);
  228.     dodgeburn_options->lut = NULL;
  229.   }
  230. }
  231.  
  232. static void
  233. dodgeburn_init (PaintCore    *paint_core,
  234.         GimpDrawable *drawable)
  235. {
  236.   /* Here we create the luts to do the painting with.*/
  237.   dodgeburn_options->lut = gimp_lut_new();
  238.   dodgeburn_make_luts (paint_core, 
  239.                dodgeburn_options->exposure,
  240.                dodgeburn_options->type,
  241.                dodgeburn_options->mode,
  242.                dodgeburn_options->lut,
  243.                drawable);
  244. }
  245.  
  246. static void 
  247. dodgeburn_make_luts (PaintCore     *paint_core,
  248.              double         db_exposure,
  249.              DodgeBurnType  type,
  250.              DodgeBurnMode  mode,
  251.              GimpLut       *lut,
  252.              GimpDrawable  *drawable)
  253. {
  254.   GimpLutFunc lut_func;
  255.   int nchannels = gimp_drawable_bytes (drawable);
  256.   static gfloat exposure;
  257.  
  258.   exposure = (db_exposure) / 100.0;
  259.  
  260.   /* make the exposure negative if burn for luts*/
  261.   if (type == BURN)
  262.     exposure = -exposure; 
  263.  
  264.   switch (mode)
  265.     {
  266.     case DODGEBURN_HIGHLIGHTS:
  267.       lut_func = dodgeburn_highlights_lut_func; 
  268.       break;
  269.     case DODGEBURN_MIDTONES:
  270.       lut_func = dodgeburn_midtones_lut_func; 
  271.       break;
  272.     case DODGEBURN_SHADOWS:
  273.       lut_func = dodgeburn_shadows_lut_func; 
  274.       break;
  275.     default:
  276.       lut_func = NULL; 
  277.       break;
  278.     }
  279.  
  280.   gimp_lut_setup_exact (lut, 
  281.     lut_func, (void *)&exposure,
  282.     nchannels);
  283. }
  284.              
  285. static void
  286. dodgeburn_modifier_key_func (Tool        *tool,
  287.                  GdkEventKey *kevent,
  288.                  gpointer     gdisp_ptr)
  289. {
  290.   switch (kevent->keyval)
  291.     {
  292.     case GDK_Alt_L: 
  293.     case GDK_Alt_R:
  294.       break;
  295.     case GDK_Shift_L: 
  296.     case GDK_Shift_R:
  297.       if (kevent->state & GDK_CONTROL_MASK)    /* reset tool toggle */
  298.     {
  299.       switch (dodgeburn_options->type)
  300.         {
  301.         case BURN:
  302.           gtk_toggle_button_set_active
  303.         (GTK_TOGGLE_BUTTON (dodgeburn_options->type_w[DODGE]), TRUE);
  304.           break;
  305.         case DODGE:
  306.           gtk_toggle_button_set_active
  307.         (GTK_TOGGLE_BUTTON (dodgeburn_options->type_w[BURN]), TRUE);
  308.           break;
  309.         default:
  310.           break;
  311.         }
  312.     }
  313.       break;
  314.     case GDK_Control_L: 
  315.     case GDK_Control_R:
  316.       if ( !(kevent->state & GDK_SHIFT_MASK) ) /* shift enables line draw mode */
  317.     {
  318.       switch (dodgeburn_options->type)
  319.         {
  320.         case BURN:
  321.           gtk_toggle_button_set_active
  322.         (GTK_TOGGLE_BUTTON (dodgeburn_options->type_w[DODGE]), TRUE);
  323.           break;
  324.         case DODGE:
  325.           gtk_toggle_button_set_active
  326.         (GTK_TOGGLE_BUTTON (dodgeburn_options->type_w[BURN]), TRUE);
  327.           break;
  328.         default:
  329.           break;
  330.         }
  331.     }
  332.       break; 
  333.     }
  334.  
  335.   tool->toggled = (dodgeburn_options->type == BURN);
  336. }
  337.  
  338. static void
  339. dodgeburn_cursor_update_func (Tool           *tool,
  340.                   GdkEventMotion *mevent,
  341.                   gpointer        gdisp_ptr)
  342. {
  343.   tool->toggled = (dodgeburn_options->type == BURN);
  344.  
  345.   paint_core_cursor_update (tool, mevent, gdisp_ptr);
  346. }
  347.  
  348. Tool *
  349. tools_new_dodgeburn (void)
  350. {
  351.   Tool * tool;
  352.   PaintCore * private;
  353.  
  354.   /*  The tool options  */
  355.   if (! dodgeburn_options)
  356.     {
  357.       dodgeburn_options = dodgeburn_options_new ();
  358.       tools_register (DODGEBURN, (ToolOptions *) dodgeburn_options);
  359.  
  360.       /*  press all default buttons  */
  361.       dodgeburn_options_reset ();
  362.     }
  363.  
  364.   tool = paint_core_new (DODGEBURN);
  365.   tool->modifier_key_func  = dodgeburn_modifier_key_func;
  366.   tool->cursor_update_func = dodgeburn_cursor_update_func;
  367.  
  368.   private = (PaintCore *) tool->private;
  369.   private->paint_func = dodgeburn_paint_func;
  370.   private->flags |= TOOL_CAN_HANDLE_CHANGING_BRUSH;
  371.  
  372.  
  373.   return tool;
  374. }
  375.  
  376. void
  377. tools_free_dodgeburn (Tool *tool)
  378. {
  379.   /* delete any luts here */
  380.   paint_core_free (tool);
  381. }
  382.  
  383. static void
  384. dodgeburn_motion (PaintCore            *paint_core,
  385.           PaintPressureOptions *pressure_options,
  386.           double                dodgeburn_exposure,
  387.           GimpLut              *lut,
  388.           GimpDrawable         *drawable)
  389. {
  390.   GImage *gimage;
  391.   TempBuf * area;
  392.   TempBuf * orig;
  393.   PixelRegion srcPR, destPR, tempPR;
  394.   guchar *temp_data;
  395.   gint opacity;
  396.   gdouble scale;
  397.  
  398.   if (! (gimage = drawable_gimage (drawable)))
  399.     return;
  400.  
  401.   /*  If the image type is indexed, don't dodgeburn  */
  402.   if ((drawable_type (drawable) == INDEXED_GIMAGE) ||
  403.       (drawable_type (drawable) == INDEXEDA_GIMAGE))
  404.     return;
  405.  
  406.   if (pressure_options->size)
  407.     scale = paint_core->curpressure;
  408.   else
  409.     scale = 1.0;
  410.  
  411.   /*  Get a region which can be used to paint to  */
  412.   if (! (area = paint_core_get_paint_area (paint_core, drawable, scale)))
  413.     return;
  414.  
  415.   /* Constant painting --get a copy of the orig drawable (with
  416.      no paint from this stroke yet) */
  417.  
  418.   {
  419.       gint x1, y1, x2, y2;
  420.       x1 = CLAMP (area->x, 0, drawable_width (drawable));
  421.       y1 = CLAMP (area->y, 0, drawable_height (drawable));
  422.       x2 = CLAMP (area->x + area->width, 0, drawable_width (drawable));
  423.       y2 = CLAMP (area->y + area->height, 0, drawable_height (drawable));
  424.  
  425.       if (!(x2 - x1) || !(y2 - y1))
  426.     return;
  427.  
  428.       /*  get the original untouched image  */
  429.       orig = paint_core_get_orig_image (paint_core, drawable, x1, y1, x2, y2);
  430.       srcPR.bytes = orig->bytes;
  431.       srcPR.x = 0; 
  432.       srcPR.y = 0;
  433.       srcPR.w = x2 - x1;
  434.       srcPR.h = y2 - y1;
  435.       srcPR.rowstride = srcPR.bytes * orig->width;
  436.       srcPR.data = temp_buf_data (orig);
  437.    }
  438.  
  439.   /* tempPR will hold the dodgeburned region*/
  440.   tempPR.bytes = srcPR.bytes;
  441.   tempPR.x = srcPR.x; 
  442.   tempPR.y = srcPR.y;
  443.   tempPR.w = srcPR.w;
  444.   tempPR.h = srcPR.h;
  445.   tempPR.rowstride = tempPR.bytes * tempPR.w;
  446.   temp_data = g_malloc (tempPR.h * tempPR.rowstride);
  447.   tempPR.data = temp_data;
  448.  
  449.   /*  DodgeBurn the region  */
  450.   gimp_lut_process (lut, &srcPR, &tempPR);
  451.  
  452.   /* The dest is the paint area we got above (= canvas_buf) */ 
  453.   destPR.bytes = area->bytes;
  454.   destPR.x = 0; destPR.y = 0;
  455.   destPR.w = area->width;
  456.   destPR.h = area->height;
  457.   destPR.rowstride = area->width * destPR.bytes;
  458.   destPR.data = temp_buf_data (area);
  459.  
  460.   /* Now add an alpha to the dodgeburned region 
  461.      and put this in area = canvas_buf */ 
  462.   if (!drawable_has_alpha (drawable))
  463.     add_alpha_region (&tempPR, &destPR);
  464.   else
  465.     copy_region (&tempPR, &destPR);
  466.  
  467.   opacity = 255 * gimp_context_get_opacity (NULL);
  468.   if (pressure_options->opacity)
  469.     opacity = opacity * 2.0 * paint_core->curpressure;
  470.  
  471.   /* Replace the newly dodgedburned area (canvas_buf) to the gimage*/   
  472.   paint_core_replace_canvas (paint_core, drawable, 
  473.                  MIN (opacity, 255),
  474.                  OPAQUE_OPACITY, 
  475.                  pressure_options->pressure ? PRESSURE : SOFT,
  476.                  scale, CONSTANT);
  477.  
  478.   g_free (temp_data);
  479. }
  480.  
  481. static void *
  482. dodgeburn_non_gui_paint_func (PaintCore    *paint_core,
  483.                   GimpDrawable *drawable,
  484.                   int           state)
  485. {
  486.   dodgeburn_motion (paint_core, &non_gui_pressure_options,
  487.             non_gui_exposure, non_gui_lut, drawable);
  488.  
  489.   return NULL;
  490. }
  491.  
  492. gboolean
  493. dodgeburn_non_gui_default (GimpDrawable *drawable,
  494.                int           num_strokes,
  495.                double       *stroke_array)
  496. {
  497.   double exposure = DODGEBURN_DEFAULT_TYPE;
  498.   DodgeBurnType type = DODGEBURN_DEFAULT_TYPE;
  499.   DodgeBurnMode mode = DODGEBURN_DEFAULT_MODE;
  500.   DodgeBurnOptions *options = dodgeburn_options;
  501.  
  502.   if (options)
  503.     {
  504.       exposure = dodgeburn_options->exposure;
  505.       type     = dodgeburn_options->type;
  506.       mode     = dodgeburn_options->mode;
  507.     }
  508.  
  509.   return dodgeburn_non_gui (drawable, exposure, type, mode, num_strokes, stroke_array);
  510. }
  511.  
  512. gboolean
  513. dodgeburn_non_gui (GimpDrawable  *drawable,
  514.            double         exposure,
  515.            DodgeBurnType  type,
  516.            DodgeBurnMode  mode,
  517.            int            num_strokes,
  518.            double        *stroke_array)
  519. {
  520.   int i;
  521.  
  522.   if (paint_core_init (&non_gui_paint_core, drawable,
  523.                stroke_array[0], stroke_array[1]))
  524.     {
  525.       /* Set the paint core's paint func */
  526.       non_gui_paint_core.paint_func = dodgeburn_non_gui_paint_func;
  527.  
  528.       non_gui_exposure = exposure;
  529.       non_gui_lut = gimp_lut_new();
  530.       dodgeburn_make_luts (&non_gui_paint_core, 
  531.                exposure,
  532.                type,
  533.                mode,
  534.                non_gui_lut,
  535.                drawable);
  536.  
  537.       non_gui_paint_core.startx = non_gui_paint_core.lastx = stroke_array[0];
  538.       non_gui_paint_core.starty = non_gui_paint_core.lasty = stroke_array[1];
  539.  
  540.       dodgeburn_non_gui_paint_func (&non_gui_paint_core, drawable, 0);
  541.  
  542.       for (i = 1; i < num_strokes; i++)
  543.     {
  544.       non_gui_paint_core.curx = stroke_array[i * 2 + 0];
  545.       non_gui_paint_core.cury = stroke_array[i * 2 + 1];
  546.  
  547.       paint_core_interpolate (&non_gui_paint_core, drawable);
  548.  
  549.       non_gui_paint_core.lastx = non_gui_paint_core.curx;
  550.       non_gui_paint_core.lasty = non_gui_paint_core.cury;
  551.     }
  552.  
  553.       /* Finish the painting */
  554.       paint_core_finish (&non_gui_paint_core, drawable, -1);
  555.  
  556.       /* Cleanup */
  557.       paint_core_cleanup ();
  558.  
  559.       gimp_lut_free (non_gui_lut);
  560.  
  561.       return TRUE;
  562.     }
  563.   else
  564.     return FALSE;
  565. }
  566.  
  567. static gfloat 
  568. dodgeburn_highlights_lut_func (void   *user_data, 
  569.                    int     nchannels, 
  570.                    int     channel, 
  571.                    gfloat  value)
  572. {
  573.    gfloat * exposure_ptr = (gfloat *)user_data;
  574.    gfloat exposure = *exposure_ptr;
  575.    gfloat factor = 1.0 + exposure * (.333333);
  576.             
  577.   if ((nchannels == 2 && channel == 1) ||
  578.       (nchannels == 4 && channel == 3))
  579.     return value;
  580.  
  581.    return factor * value;
  582. }
  583.  
  584. static gfloat 
  585. dodgeburn_midtones_lut_func (void   *user_data, 
  586.                  int     nchannels, 
  587.                  int     channel, 
  588.                  gfloat  value)
  589. {
  590.    gfloat * exposure_ptr = (gfloat *)user_data;
  591.    gfloat exposure = *exposure_ptr;
  592.    gfloat factor;
  593.  
  594.   if ((nchannels == 2 && channel == 1) ||
  595.       (nchannels == 4 && channel == 3))
  596.     return value;
  597.  
  598.    if (exposure < 0)
  599.      factor = 1.0 - exposure * (.333333);
  600.    else
  601.      factor = 1/(1.0 + exposure);
  602.    return pow (value, factor); 
  603. }
  604.  
  605. static gfloat 
  606. dodgeburn_shadows_lut_func (void   *user_data, 
  607.                 int     nchannels, 
  608.                 int     channel, 
  609.                 gfloat  value)
  610. {
  611.   gfloat * exposure_ptr = (gfloat *)user_data;
  612.   gfloat exposure = *exposure_ptr;
  613.   gfloat new_value;
  614.   gfloat factor;
  615.  
  616.   if ( (nchannels == 2 && channel == 1) ||
  617.     (nchannels == 4 && channel == 3))
  618.     return value;
  619.  
  620.   if (exposure >= 0)
  621.     {
  622.       factor = 0.333333 * exposure;
  623.       new_value =  factor + value - factor * value; 
  624.     }
  625.   else /* exposure < 0 */ 
  626.     {
  627.       factor = -0.333333 * exposure;
  628.       if (value < factor)
  629.     new_value = 0;
  630.       else /*factor <= value <=1*/
  631.     new_value = (value - factor)/(1 - factor);
  632.     }
  633.  
  634.   return new_value; 
  635. }
  636.