Daniel Bleisteiner
Daniel Bleisteiner

Reputation: 3320

How to paint a good RGB color map?

I'm trying to paint a full RGB color map that eventually will allow a user to select a color by tapping that visual map at any point. My current code is the following:

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = UIGraphicsGetCurrentContext();

    for (float x=0; x<320; x++) {
        for (float y=0; y<416; y++) {

            float r = x / 320;
            float g = y / 416;
            float b = (y < 208) ? y / 208 : (416 - y) / 208;

            CGContextSetRGBFillColor(c, r, g, b, 1.0);
            CGContextFillRect(c, CGRectMake(x, y, 1, 1));

        }
    }
}

The result is not too bad but I'm not satisfied yet. The spectrum misses bright colors including white. The reason is clear: red, green and blue will never reach 1.0 at the same time.

Screenshot of the resulting color map

Do you have any advise how to improve that map so it represents the full spectrum of the RGB color space?

Thanks for all your input!

UPDATE:

As suggested by Josh Caswell I've used the HSB color space and the following code:

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = UIGraphicsGetCurrentContext();

    int size = 20;

    for (float x=0; x<320; x+=size) {

        float s = x < 160 ? 1       : (320 - x) / 160;
        float b = x < 160 ? x / 160 : 1;

        for (float y=0; y<416; y+=size) {

            float h = y / 416;

            [[UIColor colorWithHue:h saturation:s brightness:b alpha:1.0] setFill];
            CGContextFillRect(c, CGRectMake(x, y, size, size));
        }
    }
}

This results in the following output which is perfect for my needs.

Result using HSB color space

Thanks for all input!

Upvotes: 12

Views: 1684

Answers (3)

jscs
jscs

Reputation: 64012

Well, you're trying to flatten a three-dimensional object onto a plane. An RGB color basically represents a point inside of a cube. Mapping the RGB solid onto a surface may be mathematically possible, but probably won't be particularly intuitive for this color-selection purpose.

You might have better luck using HSB, which is more like a cylinder with hue as angle around the circumference. You could "unroll" the cylinder, mapping hue to the y coordinate, then vary either brightness or saturation along the x axis -- you can do some simple testing to decide which component is more important for your application. A two-finger-swipe could be used for the third component if you felt it was necessary to include it.

HSB with saturation on X-axis:
HSB map; S on X axis

With brightness on X-axis:
HSB map; B on X axis

With saturation and brightness equal and both on X-axis:
HSB map; S=B on X axis

If you need white, which occurs when S = 0%, B = 100%, you could either stick a strip along one side, or try S = 1/B.

Upvotes: 7

Mark Ransom
Mark Ransom

Reputation: 308452

You're trying to represent a 3-dimensional color space on a 2-dimensional surface. It's unlikely that you'll find a single surface that is adequate.

You'll need a two-part selection.

Upvotes: 2

Nektarios
Nektarios

Reputation: 10351

I think a way to derive it is such:

Horizontally, for each pixel, pick a ratio of r g b such as "0, 0, 1"

Draw pixels from top to bottom with a "brightness" that goes from 0 to 1.

Derive each pixel as pixel = brightness * (r,g,b)

As you go horizontally, iterate R G B as:

000, 001, 010, 011, 100, 101, 110, 111

You can achieve this using an equation, and handle your interpolation at the same time, if you use 3 sine calculations.

This solves your problem of white and black, and gives you a lot of the color space. If you need absolutely every pixel of the color space you need to do your horizontal interpolation differently and you'll need 2^8 instead of 8 control points.

Upvotes: 2

Related Questions