Here is code to Convert RGB <-> HSB

  • My application needs to be able to make HSB adjustments to all the
    pixels in RGB NSImages that are potentially quite large. (e.g. take an
    RGB pixel, reduce the brightness by 20%, and increase the saturation
    by 50%)

    The NSColor class has excellent support for this, but you have to
    create an instance of NSColor for every value you need. I'd need to
    create several NSColor objects for every pixel on the screen, each
    time my app updates it's image. This would involved allocating and
    releasing millions of objects for each screen update.

    Instead, I found some code online that lets me convert back and forth
    between RGB and HSB values. It needed some tweaking to work with
    Cocoa. The original code was written to use hue values from 0 to 6. I
    changed it to use hue in the range 0 - 1, as is the norm in Cocoa. I
    also had to change around some of the math library calls to make them
    work in Cocoa.

    Here is the code I ended up with:

    //------------------
    //---header file
    #define RETURN_HSV(h, s, v) {HSV.H = h; HSV.S = s; HSV.V = v; return
    HSV;}

    #define RETURN_RGB(r, g, b) {RGB.R = r; RGB.G = g; RGB.B = b; return
    RGB;}

    #define UNDEFINED 0

    // Theoretically, hue 0 (pure red) is identical to hue 6 in these
    transforms. Pure

    // red always maps to 6 in this implementation. Therefore UNDEFINED
    can be

    // defined as 0 in situations where only unsigned numbers are desired.

    typedef struct {float R, G, B;} RGBType;

    typedef struct {float H, S, V;} HSVType;
    //------------------
    //--The code
    #include <math.h>

    HSVType RGB_to_HSV( RGBType RGB )
        {
        // RGB are each on [0, 1]. S and V are returned on [0, 1] and H is
        // returned on [0, 1]. Exception: H is returned UNDEFINED if S==0.
        float R = RGB.R, G = RGB.G, B = RGB.B, v, x, f;
        int i;
        HSVType HSV;
        //x = fminx(R, G, B);
        x = fminf(R, G);
        x = fminf(x, B);
        //v = fmaxf(R, G, B);
        v = fmaxf(R, G);
        v = fmaxf(v, B);
        if(v == x) RETURN_HSV(UNDEFINED, 0, v);
        f = (R == x) ? G - B : ((G == x) ? B - R : R - G);
        i = (R == x) ? 3 : ((G == x) ? 5 : 1);
        RETURN_HSV(((i - f /(v - x))/6), (v - x)/v, v);
        }

    RGBType HSV_to_RGB( HSVType HSV )
        {
        // H is given on [0, 1] or UNDEFINED. S and V are given on [0, 1].
        // RGB are each returned on [0, 1].
        float h = HSV.H * 6, s = HSV.S, v = HSV.V, m, n, f;
        int i;
        RGBType RGB;
        if (h == 0) h=.01;
        if(h == UNDEFINED) RETURN_RGB(v, v, v);
        i = floorf(h);
        f = h - i;
        if(!(i & 1)) f = 1 - f; // if i is even
        m = v * (1 - s);
        n = v * (1 - s * f);
        switch (i)
            {
            case 6:
            case 0: RETURN_RGB(v, n, m);
            case 1: RETURN_RGB(n, v, m);
            case 2: RETURN_RGB(m, v, n);
            case 3: RETURN_RGB(m, n, v);
            case 4: RETURN_RGB(n, m, v);
            case 5: RETURN_RGB(v, m, n);
            }
        RETURN_RGB(0, 0, 0);
        }
    //------------------

    I hope somebody else finds this useful.
  • On 11 Feb 2008, at 20:22, Duncan Champney wrote:

    > My application needs to be able to make HSB adjustments to all the
    > pixels in RGB NSImages that are potentially quite large. (e.g. take
    > an RGB pixel, reduce the brightness by 20%, and increase the
    > saturation by 50%)
    >
    > The NSColor class has excellent support for this, but you have to
    > create an instance of NSColor for every value you need. I'd need to
    > create several NSColor objects for every pixel on the screen, each
    > time my app updates it's image. This would involved allocating and
    > releasing millions of objects for each screen update.

    You could also take a look at CoreImage and in particular the filter
    called CIColorControls, which should let you do this pretty efficiently.

    Cheers,
      Nicko