diff --git a/src/net/torvald/colourutil/OKLabUtil.kt b/src/net/torvald/colourutil/OKLabUtil.kt new file mode 100644 index 000000000..2475987ce --- /dev/null +++ b/src/net/torvald/colourutil/OKLabUtil.kt @@ -0,0 +1,81 @@ +package net.torvald.colourutil + +import kotlin.math.atan2 +import kotlin.math.pow + +/** + * OKLab is a colour space devised by Björn Ottosson. https://bottosson.github.io/posts/oklab/ + * + * Created by minjaesong on 2022-12-02. + */ +object OKLabUtil { + + + +} + +/** + * @param L Luminosity. Scale depends on the scale of the conversion (if source Lab had 0..100, this value will also be 0..100). + * @param C Chrominance. Scale depends on the scale of the conversion. + * @param h Hue in RADIANS (-pi..pi). + */ +data class OKLCh(var L: Float = 0f, val C: Float = 0f, val h: Float = 0f, val alpha: Float = 1f) + +data class OKLab(var L: Float = 0f, val a: Float = 0f, val b: Float = 0f, val alpha: Float = 1f) { + fun toOKLCh(): OKLCh { + val c = (a*a + b*b).pow(0.5f) + val h = atan2(a, b) + + return OKLCh(L, c, h, alpha) + } + + fun toSRGB(): RGB { + val l_ = L + 0.3963377774f * a + 0.2158037573f * b + val m_ = L - 0.1055613458f * a - 0.0638541728f * b + val s_ = L - 0.0894841775f * a - 1.2914855480f * b + + val l = l_ * l_ * l_ + val m = m_ * m_ * m_ + val s = s_ * s_ * s_ + + val lrgb = RGB( + +4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s + -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s + -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s, + alpha + ) + + return lrgb.unLinearise() + } +} + +fun CIEXYZ.toOKLab(): OKLab { + val l = (0.8189330101f * this.X + 0.3618667424f * this.Y - 0.1288597137f * this.Z).pow(0.333333333333f) + val m = (0.0329845436f * this.X + 0.9293118715f * this.Y + 0.0361456387f * this.Z).pow(0.333333333333f) + val s = (0.0482003018f * this.X + 0.2643662691f * this.Y + 0.6338517070f * this.Z).pow(0.333333333333f) + + val L = 0.2104542553f*l + 0.7936177850f*m - 0.0040720468f*s + val a = 1.9779984951f*l - 2.4285922050f*m + 0.4505937099f*s + val b = 0.0259040371f*l + 0.7827717662f*m - 0.8086757660f*s + + return OKLab(L, a, b, alpha) +} + +fun RGB.toOKLab(): OKLab { + val c = this.linearise() + + val l = 0.4122214708f * c.r + 0.5363325363f * c.g + 0.0514459929f * c.b + val m = 0.2119034982f * c.r + 0.6806995451f * c.g + 0.1073969566f * c.b + val s = 0.0883024619f * c.r + 0.2817188376f * c.g + 0.6299787005f * c.b + + val l_ = l.pow(0.3333333333333f) + val m_ = m.pow(0.3333333333333f) + val s_ = s.pow(0.3333333333333f) + + + val L = 0.2104542553f * l_ + 0.7936177850f * m_ - 0.0040720468f * s_ + val a = 1.9779984951f * l_ - 2.4285922050f * m_ + 0.4505937099f * s_ + val b = 0.0259040371f * l_ + 0.7827717662f * m_ - 0.8086757660f * s_ + + return OKLab(L, a, b, c.alpha) +}