123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- //==============================================================================
- //
- // HSBSupport
- // HSBSupport
- //
- // Created by Troy Gaul on 7 Aug 2010.
- //
- // Copyright (c) 2011-2013 InfinitApps LLC: http://infinitapps.com
- // Some rights reserved: http://opensource.org/licenses/MIT
- //
- //==============================================================================
- #import "HSBSupport.h"
- //------------------------------------------------------------------------------
- float pin(float minValue, float value, float maxValue)
- {
- if (minValue > value)
- return minValue;
- else if (maxValue < value)
- return maxValue;
- else
- return value;
- }
- //------------------------------------------------------------------------------
- #pragma mark Floating point conversion
- //------------------------------------------------------------------------------
- static void hueToComponentFactors(float h, float* r, float* g, float* b)
- {
- float h_prime = h / 60.0f;
- float x = 1.0f - fabsf(fmodf(h_prime, 2.0f) - 1.0f);
-
- if (h_prime < 1.0f) {
- *r = 1;
- *g = x;
- *b = 0;
- }
- else if (h_prime < 2.0f) {
- *r = x;
- *g = 1;
- *b = 0;
- }
- else if (h_prime < 3.0f) {
- *r = 0;
- *g = 1;
- *b = x;
- }
- else if (h_prime < 4.0f) {
- *r = 0;
- *g = x;
- *b = 1;
- }
- else if (h_prime < 5.0f) {
- *r = x;
- *g = 0;
- *b = 1;
- }
- else {
- *r = 1;
- *g = 0;
- *b = x;
- }
- }
- //------------------------------------------------------------------------------
- void HSVtoRGB(float h, float s, float v, float* r, float* g, float* b)
- {
- hueToComponentFactors(h, r, g, b);
-
- float c = v * s;
- float m = v - c;
-
- *r = *r * c + m;
- *g = *g * c + m;
- *b = *b * c + m;
- }
- //------------------------------------------------------------------------------
- void RGBToHSV(float r, float g, float b, float* h, float* s, float* v, BOOL preserveHS)
- {
- float max = r;
-
- if (max < g)
- max = g;
-
- if (max < b)
- max = b;
-
- float min = r;
-
- if (min > g)
- min = g;
-
- if (min > b)
- min = b;
-
- // Brightness (aka Value)
-
- *v = max;
-
- // Saturation
-
- float sat;
-
- if (max != 0.0f) {
- sat = (max - min) / max;
- *s = sat;
- }
- else {
- sat = 0.0f;
-
- if (!preserveHS)
- *s = 0.0f; // Black, so sat is undefined, use 0
- }
-
- // Hue
-
- float delta;
-
- if (sat == 0.0f) {
- if (!preserveHS)
- *h = 0.0f; // No color, so hue is undefined, use 0
- }
- else {
- delta = max - min;
-
- float hue;
-
- if (r == max)
- hue = (g - b) / delta;
- else if (g == max)
- hue = 2 + (b - r) / delta;
- else
- hue = 4 + (r - g) / delta;
-
- hue /= 6.0f;
-
- if (hue < 0.0f)
- hue += 1.0f;
-
- if (!preserveHS || fabsf(hue - *h) != 1.0f)
- *h = hue; // 0.0 and 1.0 hues are actually both the same (red)
- }
- }
- //------------------------------------------------------------------------------
- #pragma mark Square/Bar image creation
- //------------------------------------------------------------------------------
- static UInt8 blend(UInt8 value, UInt8 percentIn255)
- {
- return (UInt8) ((int) value * percentIn255 / 255);
- }
- //------------------------------------------------------------------------------
- static CGContextRef createBGRxImageContext(int w, int h, void* data)
- {
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
-
- CGBitmapInfo kBGRxBitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst;
- // BGRA is the most efficient on the iPhone.
-
- CGContextRef context = CGBitmapContextCreate(data, w, h, 8, w * 4, colorSpace, kBGRxBitmapInfo);
-
- CGColorSpaceRelease(colorSpace);
-
- return context;
- }
- //------------------------------------------------------------------------------
- CGImageRef createSaturationBrightnessSquareContentImageWithHue(float hue)
- {
- void* data = malloc(256 * 256 * 4);
- if (data == nil)
- return nil;
-
- CGContextRef context = createBGRxImageContext(256, 256, data);
-
- if (context == nil) {
- free(data);
- return nil;
- }
-
- UInt8* dataPtr = data;
- size_t rowBytes = CGBitmapContextGetBytesPerRow(context);
-
- float r, g, b;
- hueToComponentFactors(hue, &r, &g, &b);
-
- UInt8 r_s = (UInt8) ((1.0f - r) * 255);
- UInt8 g_s = (UInt8) ((1.0f - g) * 255);
- UInt8 b_s = (UInt8) ((1.0f - b) * 255);
-
- for (int s = 0; s < 256; ++s) {
- register UInt8* ptr = dataPtr;
-
- register unsigned int r_hs = 255 - blend(s, r_s);
- register unsigned int g_hs = 255 - blend(s, g_s);
- register unsigned int b_hs = 255 - blend(s, b_s);
-
- for (register int v = 255; v >= 0; --v) {
- ptr[0] = (UInt8) (v * b_hs >> 8);
- ptr[1] = (UInt8) (v * g_hs >> 8);
- ptr[2] = (UInt8) (v * r_hs >> 8);
-
- // Really, these should all be of the form used in blend(),
- // which does a divide by 255. However, integer divide is
- // implemented in software on ARM, so a divide by 256
- // (done as a bit shift) will be *nearly* the same value,
- // and is faster. The more-accurate versions would look like:
- // ptr[0] = blend(v, b_hs);
-
- ptr += rowBytes;
- }
-
- dataPtr += 4;
- }
-
- // Return an image of the context's content:
-
- CGImageRef image = CGBitmapContextCreateImage(context);
-
- CGContextRelease(context);
- free(data);
-
- return image;
- }
- //------------------------------------------------------------------------------
- CGImageRef createHSVBarContentImage(InfComponentIndex barComponentIndex, float hsv[3])
- {
- UInt8 data[256 * 4];
-
- // Set up the bitmap context for filling with color:
-
- CGContextRef context = createBGRxImageContext(256, 1, data);
-
- if (context == nil)
- return nil;
-
- // Draw into context here:
-
- UInt8* ptr = CGBitmapContextGetData(context);
- if (ptr == nil) {
- CGContextRelease(context);
- return nil;
- }
-
- float r, g, b;
- for (int x = 0; x < 256; ++x) {
- hsv[barComponentIndex] = (float) x / 255.0f;
-
- HSVtoRGB(hsv[0] * 360.0f, hsv[1], hsv[2], &r, &g, &b);
-
- ptr[0] = (UInt8) (b * 255.0f);
- ptr[1] = (UInt8) (g * 255.0f);
- ptr[2] = (UInt8) (r * 255.0f);
-
- ptr += 4;
- }
-
- // Return an image of the context's content:
-
- CGImageRef image = CGBitmapContextCreateImage(context);
-
- CGContextRelease(context);
-
- return image;
- }
- //------------------------------------------------------------------------------
|