OSDN Git Service

reworked smudge (previously called "adapt color from image")
authorMartin Renold <martinxyz@gmx.ch>
Wed, 6 Jun 2007 15:56:23 +0000 (15:56 +0000)
committerMartin Renold <martinxyz@gmx.ch>
Wed, 6 Jun 2007 15:56:23 +0000 (15:56 +0000)
added color modifications in HSL additionally to HSV

svn://old.homeip.net/code/mypaint@506

14 files changed:
brush.py
brushes/blur.myb
brushes/o037.myb [deleted file]
brushes/o037_prev.png [deleted file]
brushes/order.conf
brushes/s007.myb [moved from brushes/s027.myb with 50% similarity]
brushes/s007_prev.png [new file with mode: 0644]
brushes/s027_prev.png [deleted file]
brushes/smudge.myb
brushsettings.py
drawwindow.py
gtkmybrush.c
helpers.c
helpers.h

index 22a84f5..23eb1ae 100644 (file)
--- a/brush.py
+++ b/brush.py
@@ -207,6 +207,8 @@ class Brush_Lowlevel(mydrawwidget.MyBrush):
                     self.set_color_rgb([int(s)/255.0 for s in rest.split()])
                 elif version <= 1 and command == 'change_radius':
                     if rest != '0.0': error = 'change_radius is not supported any more'
+                elif version <= 2 and command == 'adapt_color_from_image':
+                    if rest != '0.0': error = 'adapt_color_from_image is obsolete, ignored; use smudge and smudge_length instead'
                 elif version <= 1 and command == 'painting_time':
                     pass
                 else:
index 7ea7c6a..b2b48e1 100644 (file)
@@ -1,24 +1,37 @@
 # mypaint brush file
-color 0 0 0
+# you can edit this file and then select the brush in mypaint (again) to reload
+version 2
 opaque 0.4
-opaque_multiply 0.0 | pressure 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0
+opaque_multiply 0.0 | pressure (0.000000 0.000000), (1.000000 1.000000)
+opaque_linearize 0.0
 radius_logarithmic 2.0
-hardness 0.6 | pressure 1.0 -0.4 0.0 0.0 0.0 0.0 0.0 0.0
+hardness 0.6 | pressure (0.000000 0.000000), (1.000000 -0.400000)
 dabs_per_basic_radius 5.0
 dabs_per_actual_radius 5.0
 dabs_per_second 0.0
 radius_by_random 0.0
 speed1_slowness 0.04
 speed2_slowness 0.8
-offset_by_random 0.8 | pressure 1.0 -0.4 0.0 0.0 0.0 0.0 0.0 0.0 | speed 1.0 0.4 0.0 0.0 0.0 0.0 0.0 0.0
+speed1_gamma -6.69
+speed2_gamma 4.0
+offset_by_random 0.7 | pressure (0.000000 0.000000), (1.000000 -0.400000) | speed1 (0.000000 0.000000), (1.000000 0.200000)
 offset_by_speed 0.0
 offset_by_speed_slowness 1.0
 slow_tracking 0.0
 slow_tracking_per_dab 0.0
-color_value 0.0
-color_saturation 0.0
-color_hue 0.0
-adapt_color_from_image 1.0
-change_radius 0.0
+tracking_noise 0.0
+color_h 0.0
+color_s 0.0
+color_v 0.0
+change_color_h 0.0
+change_color_l 0.0
+change_color_hsl_s 0.0
+change_color_v 0.0
+change_color_hsv_s 0.0
+smudge 1.0
+smudge_length 0.0
 stroke_treshold 0.0
-opaque_linearize 0.0
+stroke_duration_logarithmic 4.0
+stroke_holdtime 0.0
+custom_input 0.0
+custom_input_slowness 0.0
diff --git a/brushes/o037.myb b/brushes/o037.myb
deleted file mode 100644 (file)
index 4f24c25..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# mypaint brush file
-color 214 79 36
-opaque 1.0
-opaque_multiply 0.0 | pressure 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0
-radius_logarithmic 2.0
-hardness 1.0
-dabs_per_basic_radius 0.0
-dabs_per_actual_radius 2.0
-dabs_per_second 0.0
-radius_by_random 0.0
-speed1_slowness 0.04
-speed2_slowness 1.0
-offset_by_random 0.0
-offset_by_speed 0.0
-offset_by_speed_slowness 1.0
-slow_tracking 0.0
-slow_tracking_per_dab 0.0
-color_value 0.0
-color_saturation 0.0
-color_hue 0.62
-adapt_color_from_image 0.46
-change_radius 0.0
-opaque_linearize 0.0
diff --git a/brushes/o037_prev.png b/brushes/o037_prev.png
deleted file mode 100644 (file)
index 6f51e5a..0000000
Binary files a/brushes/o037_prev.png and /dev/null differ
index 8560214..6ca5dae 100644 (file)
@@ -1,14 +1,16 @@
 # this file saves brushorder
 # the first one (upper left) will be selected at startup
-s007
 s005
 o043
 charcoal
 ink
 pencil
-s006
 smudge
 blur
+bulk
+s011
+s000
+s006
 s008
 o011
 o033
@@ -16,13 +18,13 @@ s019
 s016
 s017
 s018
-s000
 s015
-s011
+s007
 s023
-bulk
 s014
 s003
+o007
+old_b004
 bi003
 s012
 bi002
@@ -40,12 +42,9 @@ o031
 o000
 o022
 o014
-s027
 o018
 o945
-o007
 o398
-old_b004
 o512
 o501
 o665
@@ -62,7 +61,6 @@ o032
 o021
 o036
 o028
-o037
 handschrift
 o017
 old_b024
similarity index 50%
rename from brushes/s027.myb
rename to brushes/s007.myb
index 352e984..09c5672 100644 (file)
@@ -1,13 +1,13 @@
 # mypaint brush file
 # you can edit this file and then select the brush in mypaint (again) to reload
 version 2
-opaque 1.0 | speed1 (0.000000 0.000000), (1.000000 -0.200000)
-opaque_multiply 0.0 | pressure (0.000000 0.000000), (1.000000 1.000000)
+opaque 0.64 | speed1 (0.000000 0.000000), (1.000000 -0.200000)
+opaque_multiply 0.0 | pressure (0.000000 0.000000), (0.077381 0.197917), (0.229167 0.385417), (0.589286 0.510417), (1.000000 1.000000)
 opaque_linearize 0.0
-radius_logarithmic 1.6
-hardness 0.2 | pressure (0.000000 0.000000), (1.000000 0.400000)
+radius_logarithmic 1.9 | pressure (0.000000 0.400000), (1.000000 -0.600000)
+hardness 0.32 | pressure (0.000000 0.000000), (1.000000 0.400000)
 dabs_per_basic_radius 0.0
-dabs_per_actual_radius 2.0
+dabs_per_actual_radius 2.66
 dabs_per_second 0.0
 radius_by_random 0.0
 speed1_slowness 0.04
@@ -24,9 +24,12 @@ color_h 0.0
 color_s 0.0
 color_v 0.0
 change_color_h 0.0
-change_color_s 0.0
+change_color_l 0.0
+change_color_hsl_s 0.0
 change_color_v 0.0
-adapt_color_from_image 0.0 | pressure (0.000000 -0.000000), (0.033951 0.303333), (0.169753 0.110000), (0.311728 0.036667), (0.478395 0.013333), (1.000000 -0.000000)
+change_color_hsv_s 0.0
+smudge 0.02 | pressure (0.000000 1.000000), (0.166667 1.000000), (0.345238 0.843750), (0.619048 0.364583), (1.000000 -0.093750)
+smudge_length 0.28
 stroke_treshold 0.0
 stroke_duration_logarithmic 4.0
 stroke_holdtime 0.0
diff --git a/brushes/s007_prev.png b/brushes/s007_prev.png
new file mode 100644 (file)
index 0000000..c3d916e
Binary files /dev/null and b/brushes/s007_prev.png differ
diff --git a/brushes/s027_prev.png b/brushes/s027_prev.png
deleted file mode 100644 (file)
index 4322dee..0000000
Binary files a/brushes/s027_prev.png and /dev/null differ
index 8e5706e..0300f2f 100644 (file)
@@ -1,24 +1,37 @@
 # mypaint brush file
-color 0 0 0
-opaque 1.0 | speed 1.0 -0.2 0.0 0.0 0.0 0.0 0.0 0.0
-opaque_multiply 0.0 | pressure 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0
+# you can edit this file and then select the brush in mypaint (again) to reload
+version 2
+opaque 1.0 | speed1 (0.000000 0.000000), (1.000000 -0.200000)
+opaque_multiply 0.0 | pressure (0.000000 0.000000), (1.000000 1.000000)
+opaque_linearize 0.0
 radius_logarithmic 1.6
-hardness 0.2 | pressure 1.0 0.4 0.0 0.0 0.0 0.0 0.0 0.0
+hardness 0.2 | pressure (0.000000 0.000000), (1.000000 0.400000)
 dabs_per_basic_radius 0.0
 dabs_per_actual_radius 2.0
 dabs_per_second 0.0
 radius_by_random 0.0
 speed1_slowness 0.04
 speed2_slowness 0.8
+speed1_gamma 4.0
+speed2_gamma 4.0
 offset_by_random 0.0
 offset_by_speed 0.0
 offset_by_speed_slowness 1.0
 slow_tracking 0.0
 slow_tracking_per_dab 0.0
-color_value 0.0
-color_saturation 0.0
-color_hue 0.0
-adapt_color_from_image 0.65
-change_radius 0.0
+tracking_noise 0.0
+color_h 0.0
+color_s 0.0
+color_v 0.0
+change_color_h 0.0
+change_color_l 0.0
+change_color_hsl_s 0.0
+change_color_v 0.0
+change_color_hsv_s 0.0
+smudge 1.0
+smudge_length 0.35
 stroke_treshold 0.0
-opaque_linearize 0.0
+stroke_duration_logarithmic 4.0
+stroke_holdtime 0.0
+custom_input 0.0
+custom_input_slowness 0.0
index f8a2b22..ed10c79 100644 (file)
@@ -33,8 +33,8 @@ settings_list = [
     ['opaque_linearize', 'opaque linearize', True, 0.0, 0.9, 2.0, "Correct the nonlinearity introduced by blending multiple dabs on top of each other. This correction should get you a linear (\"natural\") pressure response when pressure is mapped to opaque_multiply, as it is usually done. 0.9 is good for standard strokes, set it smaller if your brush scatters a lot, or higher if you use dabs_per_second.\n0.0 the opaque value above is for the individual dabs\n1.0 the opaque value above is for the final brush stroke, assuming each pixel gets (dabs_per_radius*2) brushdabs on average during a stroke"],
     ['radius_logarithmic', 'radius', False, -2.0, 2.0, 5.0, "basic brush radius (logarithmic)\n 0.7 means 2 pixels\n 3.0 means 20 pixels"],
     ['hardness', 'hardness', False, 0.0, 0.8, 1.0, "hard brush-circle borders (setting to zero will draw nothing)"],
-    ['dabs_per_basic_radius', 'dabs per basic radius', True, 0.0, 0.0, 5.0, "how many dabs to draw while the pointer moves a distance of one brush radius (more precise: the base value of the radius)"],
-    ['dabs_per_actual_radius', 'dabs per actual radius', True, 0.0, 2.0, 5.0, "same as above, but the radius actually drawn is used, which can change dynamically"],
+    ['dabs_per_basic_radius', 'dabs per basic radius', True, 0.0, 0.0, 6.0, "how many dabs to draw while the pointer moves a distance of one brush radius (more precise: the base value of the radius)"],
+    ['dabs_per_actual_radius', 'dabs per actual radius', True, 0.0, 2.0, 6.0, "same as above, but the radius actually drawn is used, which can change dynamically"],
     ['dabs_per_second', 'dabs per second', True, 0.0, 0.0, 80.0, "dabs to draw each second, no matter how far the pointer moves"],
     ['radius_by_random', 'radius by random', False, 0.0, 0.0, 1.5, "Alter the radius randomly each dab. You can also do this with the by_random input on the radius setting. If you do it here, there are two differences:\n1) the opaque value will be corrected such that a big-radius dabs is more transparent\n2) it will not change the actual radius seen by dabs_per_actual_radius"],
     ['speed1_slowness', 'speed1 slowness', False, 0.0, 0.04, 0.2, "how slow the input speed1 is following the real speed\n0.0 change immediatly as your speed changes (not recommended, but try it)"],
@@ -51,10 +51,13 @@ settings_list = [
     ['color_h', 'color hue', True, 0.0, 0.0, 1.0, "color hue"],
     ['color_s', 'color saturation', True, -0.5, 0.0, 1.5, "color saturation"],
     ['color_v', 'color value', True, -0.5, 0.0, 1.5, "color value (brightness, intensity)"],
-    ['change_color_h', 'change color hue', False, -2.0, 0.0, 2.0, "change color hue\n-1.0 clockwise color hue shift\n 0.0 disable\n 1.0 counterclockwise hue shift"],
-    ['change_color_s', 'change color saturation', False, -2.0, 0.0, 2.0, "change the color saturation\n-1.0 more grayish\n 0.0 disable\n 1.0 more saturated"],
-    ['change_color_v', 'change color value', False, -2.0, 0.0, 2.0, "change the color value (brightness, intensity) from the choosen color\n-1.0 darker\n 0.0 disable\n 1.0 brigher"],
-    ['adapt_color_from_image', 'adapt color from image', False, 0.0, 0.0, 1.0, "slowly change the color to the one you're painting on (some kind of smudge tool)\nNote that this happens /before/ the hue/saturation/brighness adjustment above: you can get very different effects (eg brighten image) by combining with them."],
+    ['change_color_h', 'change color hue', False, -2.0, 0.0, 2.0, "Change color hue.\n-1.0 clockwise color hue shift\n 0.0 disable\n 1.0 counterclockwise hue shift"],
+    ['change_color_l', 'change color lightness (HSL)', False, -2.0, 0.0, 2.0, "Change the color lightness (luminance) using the HSL color model.\n-1.0 blacker\n 0.0 disable\n 1.0 whiter"],
+    ['change_color_hsl_s', 'change color satur. (HSL)', False, -2.0, 0.0, 2.0, "Change the color saturation using the HSL color model.\n-1.0 more grayish\n 0.0 disable\n 1.0 more saturated"],
+    ['change_color_v', 'change color value (HSV)', False, -2.0, 0.0, 2.0, "Change the color value (brightness, intensity) using the HSV color model. HSV changes are applied before HSL.\n-1.0 darker\n 0.0 disable\n 1.0 brigher"],
+    ['change_color_hsv_s', 'change color satur. (HSV)', False, -2.0, 0.0, 2.0, "Change the color saturation using the HSV color model. HSV changes are applied before HSL.\n-1.0 more grayish\n 0.0 disable\n 1.0 more saturated"],
+    ['smudge', 'smudge', False, 0.0, 0.0, 1.0, "Paint with the smudge color instead of the brush color. The smudge color is slowly changed to the color you are painting on.\n 0.0 do not use the smudge color\n 0.5 mix the smudge color with the brush color\n 1.0 use only the smudge color"],
+    ['smudge_length', 'smudge length', False, 0.0, 0.5, 1.0, "This controls how fast the smudge color becomes the color you are painting on.\n0.0 immediately change the smudge color\n1.0 never change the smudge color (FIXME: initially black!)"],
 
     ['stroke_treshold', 'stroke treshold', True, 0.0, 0.0, 0.5, "How much pressure is needed to start a stroke. This affects the stroke input only. Mypaint does not need a minimal pressure to start drawing."],
     ['stroke_duration_logarithmic', 'stroke duration', False, -1.0, 4.0, 7.0, "How far you have to move until the stroke input reaches 1.0. This value is logarithmic (negative values will not inverse the process)."],
@@ -68,11 +71,12 @@ settings_list = [
 
 
 settings_migrate = {
-    # old cname            new cname        scale function
-    'color_hue'        : ('change_color_h', lambda y: y*64.0/360.0),
-    'color_saturation' : ('change_color_s', lambda y: y*128.0/256.0),
-    'color_value'      : ('change_color_v', lambda y: y*128.0/256.0),
-    'speed_slowness'   : ('speed1_slowness', None),
+    # old cname              new cname        scale function
+    'color_hue'          : ('change_color_h', lambda y: y*64.0/360.0),
+    'color_saturation'   : ('change_color_hsv_s', lambda y: y*128.0/256.0),
+    'color_value'        : ('change_color_v', lambda y: y*128.0/256.0),
+    'speed_slowness'     : ('speed1_slowness', None),
+    'change_color_s'     : ('change_color_hsv_s', None),
     }
 
 # the states are not (yet?) exposed to the user
@@ -84,7 +88,7 @@ pressure
 dist              # "distance" moved since last dab, a new dab is drawn at 1.0
 actual_radius     # used by count_dabs_to, thus a state!
 
-smudge_r, smudge_g, smudge_b  # for adapt_color_from_image
+smudge_r, smudge_g, smudge_b
 
 actual_x, actual_y  # for slow position
 norm_dx_slow, norm_dy_slow # note: now this is dx/dt * (1/radius)
index 70b2d7f..c03d4f6 100644 (file)
@@ -163,7 +163,7 @@ class Window(gtk.Window):
             ('Undo',               None, 'Undo', '<control>Z', None, self.undo_cb),
             ('Redo',               None, 'Redo', '<control>Y', None, self.redo_cb),
             ('ModifyLastStroke',   None, 'Modify Last Stroke', 'm', None, self.modify_last_stroke_cb),
-            ('ModifyEnd',          None, 'Stop Modifying', '<control>m', None, self.modify_end_cb),
+            ('ModifyEnd',          None, 'Stop Modifying', 'n', None, self.modify_end_cb),
             ('LowerLastStroke',    None, 'Lower Last Stroke (Slow!)', 'Page_Down', None, self.lower_or_raise_last_stroke_cb),
             ('RaiseLastStroke',    None, 'Raise Last Stroke', 'Page_Up', None, self.lower_or_raise_last_stroke_cb),
 
@@ -173,8 +173,8 @@ class Window(gtk.Window):
             ('Darker',       None, 'Darker', None, None, self.darker_cb),
             ('Bigger',       None, 'Bigger', 'f', None, self.brush_bigger_cb),
             ('Smaller',      None, 'Smaller', 'd', None, self.brush_smaller_cb),
-            ('MoreOpaque',   None, 'More Opaque', None, None, self.more_opaque_cb),
-            ('LessOpaque',   None, 'Less Opaque', None, None, self.less_opaque_cb),
+            ('MoreOpaque',   None, 'More Opaque', 's', None, self.more_opaque_cb),
+            ('LessOpaque',   None, 'Less Opaque', 'a', None, self.less_opaque_cb),
             ('PickColor',    None, 'Pick Color', 'r', None, self.pick_color_cb),
             ('ChangeColor',  None, 'Change Color', 'v', None, self.change_color_cb),
 
index 9ca2dd3..92b782e 100644 (file)
@@ -370,8 +370,8 @@ int brush_prepare_and_draw_dab (GtkMyBrush * b, GtkMySurfaceOld * s, Rect * bbox
 
   opaque = settings[BRUSH_OPAQUE] * settings[BRUSH_OPAQUE_MULTIPLY];
   if (opaque >= 1.0) opaque = 1.0;
-  //if (opaque <= 0.0) opaque = 0.0;
-  if (opaque <= 0.0) return 0;
+  if (opaque <= 0.0) opaque = 0.0;
+  //if (opaque == 0.0) return 0; <-- bad idea: need to update smudge state.
   if (settings[BRUSH_OPAQUE_LINEARIZE]) {
     // OPTIMIZE: no need to recalculate this for each dab
     float alpha, beta, alpha_dab, beta_dab;
@@ -434,36 +434,63 @@ int brush_prepare_and_draw_dab (GtkMyBrush * b, GtkMySurfaceOld * s, Rect * bbox
   // color part
 
   float color_h, color_s, color_v;
-  if (!settings[BRUSH_ADAPT_COLOR_FROM_IMAGE]) {
+  if (settings[BRUSH_SMUDGE] <= 0.0) {
     // normal case (do not smudge)
-    // but to allow a smooth transition to smudging, ... FIXME: do what?
     color_h = b->settings[BRUSH_COLOR_H]->base_value;
     color_s = b->settings[BRUSH_COLOR_S]->base_value;
     color_v = b->settings[BRUSH_COLOR_V]->base_value;
-  } else {
-    // ignore the brush color, only use the smudge state
+  } else if (settings[BRUSH_SMUDGE] >= 1.0) {
+    // smudge only (ignore the original color)
     color_h = b->states[STATE_SMUDGE_R];
     color_s = b->states[STATE_SMUDGE_G];
     color_v = b->states[STATE_SMUDGE_B];
     rgb_to_hsv_float (&color_h, &color_s, &color_v);
+  } else {
+    // mix (in RGB) the smudge color with the brush color
+    color_h = b->settings[BRUSH_COLOR_H]->base_value;
+    color_s = b->settings[BRUSH_COLOR_S]->base_value;
+    color_v = b->settings[BRUSH_COLOR_V]->base_value;
+    // XXX clamp??!? before this call?
+    hsv_to_rgb_float (&color_h, &color_s, &color_v);
+    float fac = settings[BRUSH_SMUDGE];
+    color_h = (1-fac)*color_h + fac*b->states[STATE_SMUDGE_R];
+    color_s = (1-fac)*color_s + fac*b->states[STATE_SMUDGE_G];
+    color_v = (1-fac)*color_v + fac*b->states[STATE_SMUDGE_B];
+    rgb_to_hsv_float (&color_h, &color_s, &color_v);
+  }
 
-    { // update the smudge state
-      int px, py;
-      guchar *rgb;
-      float v = settings[BRUSH_ADAPT_COLOR_FROM_IMAGE];
-      px = ROUND(x); px = CLAMP(px, 0, s->w-1);
-      py = ROUND(y); py = CLAMP(py, 0, s->h-1);
-      rgb = PixelXY(s, px, py);
-      b->states[STATE_SMUDGE_R] = (1-v)*b->states[STATE_SMUDGE_R] + v*rgb[0]/255.0;
-      b->states[STATE_SMUDGE_G] = (1-v)*b->states[STATE_SMUDGE_G] + v*rgb[1]/255.0;
-      b->states[STATE_SMUDGE_B] = (1-v)*b->states[STATE_SMUDGE_B] + v*rgb[2]/255.0;
-    }
+  // update the smudge state
+  if (settings[BRUSH_SMUDGE_LENGTH] < 1.0) {
+    float fac = settings[BRUSH_SMUDGE_LENGTH];
+    if (fac < 0.0) fac = 0;
+    int px, py;
+    guchar *rgb;
+    px = ROUND(x); px = CLAMP(px, 0, s->w-1);
+    py = ROUND(y); py = CLAMP(py, 0, s->h-1);
+    rgb = PixelXY(s, px, py);
+    b->states[STATE_SMUDGE_R] = fac*b->states[STATE_SMUDGE_R] + (1-fac)*rgb[0]/255.0;
+    b->states[STATE_SMUDGE_G] = fac*b->states[STATE_SMUDGE_G] + (1-fac)*rgb[1]/255.0;
+    b->states[STATE_SMUDGE_B] = fac*b->states[STATE_SMUDGE_B] + (1-fac)*rgb[2]/255.0;
   }
 
+  // HSV color change
   color_h += settings[BRUSH_CHANGE_COLOR_H];
-  color_s += settings[BRUSH_CHANGE_COLOR_S];
+  color_s += settings[BRUSH_CHANGE_COLOR_HSV_S];
   color_v += settings[BRUSH_CHANGE_COLOR_V];
-  
+
+
+  // HSL color change
+  if (settings[BRUSH_CHANGE_COLOR_L] || settings[BRUSH_CHANGE_COLOR_HSL_S]) {
+    float h, s, l;
+    // (calculating way too much here, can be optimized if neccessary)
+    hsv_to_rgb_float (&color_h, &color_s, &color_v);
+    rgb_to_hsl_float (&color_h, &color_s, &color_v);
+    color_v += settings[BRUSH_CHANGE_COLOR_L];
+    color_s += settings[BRUSH_CHANGE_COLOR_HSL_S];
+    hsl_to_rgb_float (&color_h, &color_s, &color_v);
+    rgb_to_hsv_float (&color_h, &color_s, &color_v);
+  } 
+
   { // final calculations
     gint c[3];
 
index 2a951f3..caa1291 100644 (file)
--- a/helpers.c
+++ b/helpers.c
@@ -5,6 +5,10 @@
  * it under the terms of the GNU General Public License.
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY. See the COPYING file for more details.
+ *
+ * This file contains some modified code from the GIMP:
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ * Adapted 2007 by Martin Renold to fit into MyPaint.
  */
 
 #include "helpers.h"
@@ -195,7 +199,7 @@ hsv_to_rgb_int (gint *hue,
 }
 
 
-// inputs and outputs are all [0,1]
+// (from gimp_rgb_to_hsv)
 void
 rgb_to_hsv_float (float *r_, float *g_, float *b_)
 {
@@ -207,6 +211,10 @@ rgb_to_hsv_float (float *r_, float *g_, float *b_)
   g = *g_;
   b = *b_;
 
+  r = CLAMP(r, 0.0, 1.0);
+  g = CLAMP(g, 0.0, 1.0);
+  b = CLAMP(b, 0.0, 1.0);
+
   max = MAX3(r, g, b);
   min = MIN3(r, g, b);
 
@@ -245,6 +253,222 @@ rgb_to_hsv_float (float *r_, float *g_, float *b_)
   *b_ = v;
 }
 
+// (from gimp_hsv_to_rgb)
+void
+hsv_to_rgb_float (float *h_, float *s_, float *v_)
+{
+  gint    i;
+  gdouble f, w, q, t;
+  float h, s, v;
+  float r, g, b;
+
+  h = *h_;
+  s = *s_;
+  v = *v_;
+
+  h = h - floor(h);
+  s = CLAMP(s, 0.0, 1.0);
+  v = CLAMP(v, 0.0, 1.0);
+
+  gdouble hue;
+
+  if (s == 0.0)
+    {
+      r = v;
+      g = v;
+      b = v;
+    }
+  else
+    {
+      hue = h;
+
+      if (hue == 1.0)
+        hue = 0.0;
+
+      hue *= 6.0;
+
+      i = (gint) hue;
+      f = hue - i;
+      w = v * (1.0 - s);
+      q = v * (1.0 - (s * f));
+      t = v * (1.0 - (s * (1.0 - f)));
+
+      switch (i)
+        {
+        case 0:
+          r = v;
+          g = t;
+          b = w;
+          break;
+        case 1:
+          r = q;
+          g = v;
+          b = w;
+          break;
+        case 2:
+          r = w;
+          g = v;
+          b = t;
+          break;
+        case 3:
+          r = w;
+          g = q;
+          b = v;
+          break;
+        case 4:
+          r = t;
+          g = w;
+          b = v;
+          break;
+        case 5:
+          r = v;
+          g = w;
+          b = q;
+          break;
+        }
+    }
+
+  *h_ = r;
+  *s_ = g;
+  *v_ = b;
+}
+
+// gimp_rgb_to_hsl:
+void
+rgb_to_hsl_float (float *r_, float *g_, float *b_)
+{
+  gdouble max, min, delta;
+
+  float h, s, l;
+  float r, g, b;
+
+  r = *r_;
+  g = *g_;
+  b = *b_;
+
+  r = CLAMP(r, 0.0, 1.0);
+  g = CLAMP(g, 0.0, 1.0);
+  b = CLAMP(b, 0.0, 1.0);
+
+  max = MAX3(r, g, b);
+  min = MIN3(r, g, b);
+
+  l = (max + min) / 2.0;
+
+  if (max == min)
+    {
+      s = 0.0;
+      h = 0.0; //GIMP_HSL_UNDEFINED;
+    }
+  else
+    {
+      if (l <= 0.5)
+        s = (max - min) / (max + min);
+      else
+        s = (max - min) / (2.0 - max - min);
+
+      delta = max - min;
+
+      if (delta == 0.0)
+        delta = 1.0;
+
+      if (r == max)
+        {
+          h = (g - b) / delta;
+        }
+      else if (g == max)
+        {
+          h = 2.0 + (b - r) / delta;
+        }
+      else if (b == max)
+        {
+          h = 4.0 + (r - g) / delta;
+        }
+
+      h /= 6.0;
+
+      if (h < 0.0)
+        h += 1.0;
+    }
+
+  *r_ = h;
+  *g_ = s;
+  *b_ = l;
+}
+
+static double
+hsl_value (gdouble n1,
+           gdouble n2,
+           gdouble hue)
+{
+  gdouble val;
+
+  if (hue > 6.0)
+    hue -= 6.0;
+  else if (hue < 0.0)
+    hue += 6.0;
+
+  if (hue < 1.0)
+    val = n1 + (n2 - n1) * hue;
+  else if (hue < 3.0)
+    val = n2;
+  else if (hue < 4.0)
+    val = n1 + (n2 - n1) * (4.0 - hue);
+  else
+    val = n1;
+
+  return val;
+}
+
+
+/**
+ * gimp_hsl_to_rgb:
+ * @hsl: A color value in the HSL colorspace
+ * @rgb: The value converted to a value in the RGB colorspace
+ *
+ * Convert a HSL color value to an RGB color value.
+ **/
+void
+hsl_to_rgb_float (float *h_, float *s_, float *l_)
+{
+  float h, s, l;
+  float r, g, b;
+
+  h = *h_;
+  s = *s_;
+  l = *l_;
+
+  h = h - floor(h);
+  s = CLAMP(s, 0.0, 1.0);
+  l = CLAMP(l, 0.0, 1.0);
+
+  if (s == 0)
+    {
+      /*  achromatic case  */
+      r = l;
+      g = l;
+      b = l;
+    }
+  else
+    {
+      gdouble m1, m2;
+
+      if (l <= 0.5)
+        m2 = l * (1.0 + s);
+      else
+        m2 = l + s - l * s;
+
+      m1 = 2.0 * l - m2;
+
+      r = hsl_value (m1, m2, h * 6.0 + 2.0);
+      g = hsl_value (m1, m2, h * 6.0);
+      b = hsl_value (m1, m2, h * 6.0 - 2.0);
+    }
+
+  *h_ = r;
+  *s_ = g;
+  *l_ = b;
+}
 
 // tested, copied from my mass project
 void ExpandRectToIncludePoint(Rect * r, int x, int y) 
index 1c86698..a9558a8 100644 (file)
--- a/helpers.h
+++ b/helpers.h
@@ -26,6 +26,9 @@ gdouble rand_gauss (GRand * rng);
 void rgb_to_hsv_int (gint *red /*h*/, gint *green /*s*/, gint *blue /*v*/);
 void hsv_to_rgb_int (gint *hue /*r*/, gint *saturation /*g*/, gint *value /*b*/);
 void rgb_to_hsv_float (float *r_ /*h*/, float *g_ /*s*/, float *b_ /*v*/);
+void hsv_to_rgb_float (float *h_, float *s_, float *v_);
+void hsl_to_rgb_float (float *h_, float *s_, float *l_);
+void rgb_to_hsl_float (float *r_, float *g_, float *b_);
 
 
 typedef struct { int x, y, w, h; } Rect;