Skip to content

Instantly share code, notes, and snippets.

@FredrikSjoberg
Last active April 11, 2024 11:22
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save FredrikSjoberg/cdea97af68c6bdb0a89e3aba57a966ce to your computer and use it in GitHub Desktop.
Save FredrikSjoberg/cdea97af68c6bdb0a89e3aba57a966ce to your computer and use it in GitHub Desktop.
Color space conversion between RGB and HSV
// https://www.cs.rit.edu/~ncs/color/t_convert.html
struct RGB {
// Percent
let r: Float // [0,1]
let g: Float // [0,1]
let b: Float // [0,1]
static func hsv(r: Float, g: Float, b: Float) -> HSV {
let min = r < g ? (r < b ? r : b) : (g < b ? g : b)
let max = r > g ? (r > b ? r : b) : (g > b ? g : b)
let v = max
let delta = max - min
guard delta > 0.00001 else { return HSV(h: 0, s: 0, v: max) }
guard max > 0 else { return HSV(h: -1, s: 0, v: v) } // Undefined, achromatic grey
let s = delta / max
let hue: (Float, Float) -> Float = { max, delta -> Float in
if r == max { return (g-b)/delta } // between yellow & magenta
else if g == max { return 2 + (b-r)/delta } // between cyan & yellow
else { return 4 + (r-g)/delta } // between magenta & cyan
}
let h = hue(max, delta) * 60 // In degrees
return HSV(h: (h < 0 ? h+360 : h) , s: s, v: v)
}
static func hsv(rgb: RGB) -> HSV {
return hsv(rgb.r, g: rgb.g, b: rgb.b)
}
var hsv: HSV {
return RGB.hsv(self)
}
}
struct RGBA {
let a: Float
let rgb: RGB
init(r: Float, g: Float, b: Float, a: Float) {
self.a = a
self.rgb = RGB(r: r, g: g, b: b)
}
}
struct HSV {
let h: Float // Angle in degrees [0,360] or -1 as Undefined
let s: Float // Percent [0,1]
let v: Float // Percent [0,1]
static func rgb(h: Float, s: Float, v: Float) -> RGB {
if s == 0 { return RGB(r: v, g: v, b: v) } // Achromatic grey
let angle = (h >= 360 ? 0 : h)
let sector = angle / 60 // Sector
let i = floor(sector)
let f = sector - i // Factorial part of h
let p = v * (1 - s)
let q = v * (1 - (s * f))
let t = v * (1 - (s * (1 - f)))
switch(i) {
case 0:
return RGB(r: v, g: t, b: p)
case 1:
return RGB(r: q, g: v, b: p)
case 2:
return RGB(r: p, g: v, b: t)
case 3:
return RGB(r: p, g: q, b: v)
case 4:
return RGB(r: t, g: p, b: v)
default:
return RGB(r: v, g: p, b: q)
}
}
static func rgb(hsv: HSV) -> RGB {
return rgb(hsv.h, s: hsv.s, v: hsv.v)
}
var rgb: RGB {
return HSV.rgb(self)
}
/// Returns a normalized point with x=h and y=v
var point: CGPoint {
return CGPoint(x: CGFloat(h/360), y: CGFloat(v))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment