gegl-developer  

[Gegl-developer] New to GEGL, and HSL plugin

Andrew Pendleton
Fri, 02 Feb 2007 23:16:39 -0800

I'm a college student, and don't know a whole lot about GEGL, or image
processing, in general, but would like to get into it, a bit, and maybe to
help hasten along the arrival of the next-generation Gimp or whatever.  With
that in mind, I'm starting to feel my way around the codebase, in hopes of
being able to make some useful contributions.

As a getting-started project, I wrote a rough hue/saturation/lightness
adjustment operation, which I've attached, and was hoping maybe I could get
some feedback on it, to see if I'm getting the write idea about this task,
in particular, and about the "GEGL way of doing things," in general.  A few
specific questions:

* In the operation, I convert from 32-bit float rgba to HSL, do the
operations, and convert back again.  It occured to me, later, that perhaps
this was something that should be done as a colorspace conversion in babl,
instead, though it doesn't look like HSL is a currently supported babl
colorspace.  Is that correct, or is this legit?

* Are adjustments to lightness and saturation usually multiplicative?  I
started out having all of the adjustments be additive, and while that worked
for hue, it gave results for lightness and saturation that were markedly
different from those of the current Gimp.  At present, they add the factor
times the current value, and that seems to approximate the Gimp's behavior
for saturation, though not for lightness.  Perhaps I just don't have the
minimum and maximum values of my ranges set appropriately?  I may just dig
into the current Gimp code and see how they do it...

* Is there a standard for coding style in GEGL?  It seems that two-space
indents are common, but other than that, other practices don't seem entirely
consistent, and I'd like to format things appropriately, as I go, if
possible.

* Is there a TODO, somewhere?  I saw that one existed in earlier CVS
iterations, but it seems to be gone from current SVN.  I picked HSL because
I figured it wouldn't be too hard, and there wasn't one, but being able to
spend time on things that actually need doing would be good.

Thanks,
Andrew
/* This file is an image processing operation for GEGL
 *
 * GEGL is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * GEGL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with GEGL; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * Copyright 2007 Andrew Pendleton
 */
#if GEGL_CHANT_PROPERTIES

gegl_chant_double (hue,      -180.0, 180.0, 0.0,
   "Amount to adjust hue (in degrees)")
gegl_chant_double (saturation,    -1.0,  1.0, 0.0,
   "Amount to adjust saturation")
gegl_chant_double (lightness,    -1.0,  1.0, 0.0,
   "Amount to adjust lightness")

#else

#define GEGL_CHANT_POINT_FILTER
#define GEGL_CHANT_NAME          hsl
#define GEGL_CHANT_DESCRIPTION   "Adjusts the hue, saturation, and/or lightness of the image"
#define GEGL_CHANT_SELF          "hsl.c"
#define GEGL_CHANT_CATEGORIES    "color"
#define GEGL_CHANT_INIT
#include "gegl-chant.h"

static void init (GeglChantOperation *self)
{
  /* set the babl format this operation prefers to work on */
  GEGL_OPERATION_POINT_FILTER (self)->format = babl_format ("RGBA float");
}

static gboolean
process (GeglOperation *op,
         void          *in_buf,
         void          *out_buf,
         glong          samples) 
{
  gint i;
  gfloat *in  = in_buf;
  gfloat *out = out_buf;
  GeglChantOperation *self;
  
  self = GEGL_CHANT_OPERATION (op);
  
  /* formulas for this implementation were obtained from
    http://en.wikipedia.org/wiki/HLS_color_space */
  
  for (i=0; i<samples; i++)
    {
      
      gfloat r, g, b, h, s, l, a, max, min, t1, t2, t3r, t3g, t3b;
      r = in[0];
      g = in[1];
      b = in[2];
      a = in[3];
      
      /* find min and max of the RGB values */
      if (r > g)
      {
        if (r > b)
        {
          max = r;
          if (b > g)
          {
            min = g;
          }
          else
          {
            min = b;
          }
        }
        else
        {
          max = b;
          min = g;
        }
      }
      else
      {
        if (b > r)
        {
          min = r;
          if (b > g)
          {
            max = b;
          }
          else
          {
            max = g;
          }
        }
        else
        {
          max = g;
          min = r;
        }
      }
      
      /* convert to hsl */
      if (max == min)
      {
        h = 0;
      }
      else if (max == r)
      {
        h = (g - b) / (max - min);
        if (g < b)
        {
          h += 6;
        }
      }
      else if (max == g)
      {
        h = (b - r) / (max - min) + 2;
      }
      else
      {
        h = (r - g) / (max - min) + 4;
      }
      
      l = 0.5 * (max + min);
      
      if (l == 0 || max == min)
      {
        s = 0;
      }
      else if (0 < l && l <= 0.5)
      {
        s = (max - min) / (2 * l);
      }
      else
      {
        s = (max - min) / (2 - 2 * l);
      }
      
      /* adjust the HSL values based on input */
      h += (self->hue / 60);
      s += self->saturation * s;
      l += self->lightness * l;
      
      /* check that values are within range */
      if (h >= 6) h -= 6;
      if (h < 0) h += 6;
      if (s > 1) s = 1;
      if (s < 0) s = 0;
      if (l > 1) l = 1;
      if (l < 0) l = 0;
      
      /* convert back to rgb */
      t2 = (l < 0.5 ? l * (1.0 + s) : l + s - (l * s));
      t1 = (2 * l - t2);
      
      t3r = h + 2;
      t3g = h;
      t3b = h - 2;
      
      if (t3r < 0) t3r += 6;
      if (t3b < 0) t3b += 6;
      if (t3r > 6) t3r -= 6;
      if (t3b > 6) t3b -= 6;
      
      if (t3r < 1)
      {
        r = t1 + ((t2 - t1) * t3r);
      }
      else if (1 <= t3r && t3r < 3)
      {
        r = t2;
      }
      else if (3 <= t3r && t3r < 4)
      {
        r = t1 + ((t2 - t1) * (4 - t3r));
      }
      else
      {
        r = t1;
      }
      
      if (t3g < 1)
      {
        g = t1 + ((t2 - t1) * t3g);
      }
      else if (1 <= t3g && t3g < 3)
      {
        g = t2;
      }
      else if (3 <= t3g && t3g < 4)
      {
        g = t1 + ((t2 - t1) * (4 - t3g));
      }
      else
      {
        g = t1;
      }
      
      if (t3b < 1)
      {
        b = t1 + ((t2 - t1) * t3b);
      }
      else if (1 <= t3b && t3b < 3)
      {
        b = t2;
      }
      else if (3 <= t3b && t3b < 4)
      {
        b = t1 + ((t2 - t1) * (4 - t3b));
      }
      else
      {
        b = t1;
      }
      
      out[0] = r;
      out[1] = g;
      out[2] = b;
      
      out[3]=in[3];
      in += 4;
      out+= 4;
    }
  return TRUE;
}

#endif
_______________________________________________
Gegl-developer mailing list
Gegl-developer@lists.XCF.Berkeley.EDU
https://lists.XCF.Berkeley.EDU/mailman/listinfo/gegl-developer