Skip to content

Instantly share code, notes, and snippets.

@nadar71
Created October 21, 2020 09:37
Show Gist options
  • Save nadar71/626a9261b904b5a99285277d3d74e24d to your computer and use it in GitHub Desktop.
Save nadar71/626a9261b904b5a99285277d3d74e24d to your computer and use it in GitHub Desktop.
From Argb to CIE XY and viceversa
import android.graphics.Color
import android.os.Build
import android.util.Log
import androidx.annotation.ColorInt
import it.diceworld.dicehome.utility.common.extensions.round
import kotlin.math.pow
class ColorConverter {
companion object {
val TAG = ColorConverter::class.java.simpleName
// ---------------------------------------------------------------------------------------------
// From Argb to hex
// Convert from ARGB to color rgb lamp format 0x1234#0xabdf# for cloud
fun fromARGBtoCloud(@ColorInt color: Int):String{
return fromCIEXYtoHexString(fromArgbToCIEXY(color))
}
// convert from argb to CIE XY 1931 (bidimensional version for CIE XYZ 1931)
// specific for hue philips, works with good aproximation for ours lamp too :
// https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d
// https://github.com/johnciech/PhilipsHueSDK/blob/master/ApplicationDesignNotes/RGB%20to%20xy%20Color%20conversion.md
fun fromArgbToCIEXY(@ColorInt color: Int): DoubleArray{
// val resultArray = DoubleArray(3)
// get r,g,b component
val red = Color.red(color)
val green = Color.green(color)
val blue = Color.blue(color)
val redN = if (red > 0.04045) ((red + 0.055) / (1.0 + 0.055)).pow(2.4) else red / 12.92
val greenN = if (green > 0.04045) ((green + 0.055) / (1.0 + 0.055)).pow(2.4) else green / 12.92
val blueN = if (blue > 0.04045) ((blue + 0.055) / (1.0 + 0.055)).pow(2.4) else blue / 12.92
val xAxis = (0.649926 * redN) + (0.103455 * greenN) + (0.197109 * blueN)
val yAxis = (0.234327 * redN) + (0.743075 * greenN) + (0.022598 * blueN)
val zAxis = (0.0000000 * redN) + (0.053077 * greenN) + (1.035763 * blueN)
val xValue = (xAxis / (xAxis + yAxis + zAxis)).round(4)
val yValue = (yAxis / (xAxis + yAxis + zAxis)).round(4)
return doubleArrayOf(xValue,yValue)
}
// convert from CIE XY 1931 (bidimensional version for CIE XYZ 1931) to hex string format
// 0x1234#0xabdf# suitable for cloud to changing rgb lamp color
fun fromCIEXYtoHexString(input: DoubleArray):String{
val result = StringBuilder()
for(number in input){
// convert to int
val toBeHexConverted = (Math.floor(number * 65536)).toInt()
result.append("0x${toBeHexConverted.toString(16)}#")
}
return result.toString()
}
// ---------------------------------------------------------------------------------------------
// From hex to Argb
// Convert from color rgb lamp format 0x1234, 0xabdf for command to ARGB
fun fromCloudtoARGB(colorCloud: String, brightness: Double ): Int {
return fromCIEXYToArgb(fromHexStringToCIEXY(colorCloud),brightness)
}
// convert from hex string format 0x1234, 0xabdf suitable for cloud
// to CIE XY 1931 (bidimensional version for CIE XYZ 1931)
fun fromHexStringToCIEXY(colorCloud: String):DoubleArray{
val resDouble = DoubleArray(2)
val colorSeq = colorCloud.replace("0x", "")
.replace("\\s".toRegex(), "")
.split("#")
.filterNot { it.isEmpty() }
for( i in colorSeq.indices){
resDouble[i] = colorSeq[i].toInt(16).toDouble()
resDouble[i] = (Math.floor(resDouble[i]/65536))
resDouble[i].round(4)
}
return resDouble
}
// convert from CIE XY 1931 (bidimensional version for CIE XYZ 1931) to argb
// specific for hue philips, works with good aproximation for ours lamp too :
// https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d
// https://github.com/johnciech/PhilipsHueSDK/blob/master/ApplicationDesignNotes/RGB%20to%20xy%20Color%20conversion.md
fun fromCIEXYToArgb(cieXY :DoubleArray, brightness: Double) : Int {
var resultArgb: Int
val normalizedBrightness = brightness/100
val xValue = cieXY[0]
val yValue = cieXY[1]
val zValue = 1.0 - xValue - yValue
val yAxis = normalizedBrightness
val xAxis = (yAxis / yValue) * xValue
val zAxis = (yAxis / yValue) * zValue
// sRGB D65 conversion
var red = (xAxis * 1.612) - (yAxis * 0.203) - (zAxis * 0.302)
var green = (-xAxis * 0.509) + (yAxis * 1.412) + (zAxis * 0.066)
var blue = (xAxis * 0.026) - (yAxis * 0.072) + (zAxis * 0.962)
if (red > blue && red > green && red > 1.0) {
// red is too big
green /= red
blue /= red
red = 1.0
} else if (green > blue && green > red && green > 1.0) {
// green is too big
red /= green
blue /= green
green = 1.0
} else if (blue > red && blue > green && blue > 1.0) {
// blue is too big
red /= blue
green /= blue
blue = 1.0
}
// Apply gamma correction
red = if (red <= 0.0031308) 12.92 * red else (1.0 + 0.055) * red.pow((1.0 / 2.4)) - 0.055
green = if (green <= 0.0031308) 12.92 * green else (1.0 + 0.055) * green.pow((1.0 / 2.4)) - 0.055
blue = if (blue <= 0.0031308) 12.92 * blue else (1.0 + 0.055) * blue.pow((1.0 / 2.4)) - 0.055
if (red > blue && red > green) {
// red is biggest
if (red > 1.0) {
green /= red
blue /= red
red = 1.0
}
} else if (green > blue && green > red) {
// green is biggest
if (green > 1.0) {
red /= green
blue /= green
green = 1.0
}
} else if (blue > red && blue > green) {
// blue is biggest
if (blue > 1.0) {
red /= blue
green /= blue
blue = 1.0
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
resultArgb = Color.argb(1.0f, red.toFloat(), green.toFloat(), blue.toFloat())
} else {
resultArgb = ((1.0.toInt() and 0xff) shl 24) or
((red.toInt() and 0xff) shl 16) or
((green.toInt() and 0xff) shl 8) or
((blue.toInt() and 0xff))
}
Log.i(Utility.TAG, "red: $red, green: $green, blue: $blue")
Log.i(Utility.TAG, "CIE1931 to RGB converted color: $resultArgb")
return resultArgb
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment