All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.HEXAColor.kt Maven / Gradle / Ivy

There is a newer version: 0.22.3
Show newest version
package dev.inmo.micro_utils.colors.common

import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline
import kotlin.math.floor

/**
 * Wrapper for RGBA colors. Receiving [UInt] in main constructor. Each part in main constructor
 * configured with `0x00 - 0xff` range. Examples:
 *
 * * Red: `0xff0000ffu`
 * * Red (0.5 capacity): `0xff000088u`
 *
 * Anyway it is recommended to use
 *
 * @param hexaUInt rgba [UInt] in format `0xFFEEBBAA` where FF - red, EE - green, BB - blue` and AA - alpha
 */
@Serializable
@JvmInline
value class HEXAColor (
    val hexaUInt: UInt
) : Comparable {
    /**
     * @returns [hexaUInt] as a string with format `#FFEEBBAA` where FF - red, EE - green, BB - blue and AA - alpha
     */
    val hexa: String
        get() = "#${hexaUInt.toString(16).padStart(8, '0')}"

    /**
     * @returns [hexaUInt] as a string with format `#FFEEBB` where FF - red, EE - green and BB - blue
     */
    val hex: String
        get() = hexa.take(7)
    /**
     * @returns [hexaUInt] as a string with format `#AAFFEEBB` where AA - alpha, FF - red, EE - green and BB - blue
     */
    val ahex: String
        get() = "#${a.toString(16).padStart(2, '2')}${hex.drop(1)}"
    val rgba: String
        get() = "rgba($r,$g,$b,${aOfOne.toString().take(5)})"
    val rgb: String
        get() = "rgb($r,$g,$b)"
    val shortHex: String
        get() = "#${r.shortPart()}${g.shortPart()}${b.shortPart()}"
    val shortHexa: String
        get() = "$shortHex${a.shortPart()}"
    val rgbUInt: UInt
        get() = (hexaUInt / 256u)
    val rgbInt: Int
        get() = rgbUInt.toInt()
    val ahexUInt
        get() = (a * 0x1000000).toUInt() + rgbUInt

    val r: Int
        get() = ((hexaUInt and 0xff000000u) / 0x1000000u).toInt()
    val g: Int
        get() = ((hexaUInt and 0x00ff0000u) / 0x10000u).toInt()
    val b: Int
        get() = ((hexaUInt and 0x0000ff00u) / 0x100u).toInt()
    val a: Int
        get() = ((hexaUInt and 0x000000ffu)).toInt()
    val aOfOne: Float
        get() = a.toFloat() / (0xff)
    init {
        require(hexaUInt in 0u ..0xffffffffu)
    }

    constructor(r: Int, g: Int, b: Int, a: Int) : this(
        ((r * 0x1000000).toLong() + g * 0x10000 + b * 0x100 + a).toUInt()
    ) {
        require(r in 0 ..0xff)
        require(g in 0 ..0xff)
        require(b in 0 ..0xff)
        require(a in 0 ..0xff)
    }

    constructor(r: Int, g: Int, b: Int, aOfOne: Float = 1f) : this(
        r = r, g = g, b = b, a = (aOfOne * 0xff).toInt()
    )

    override fun toString(): String {
        return hexa
    }

    override fun compareTo(other: HEXAColor): Int = (hexaUInt - other.hexaUInt).coerceIn(Int.MIN_VALUE.toUInt(), Int.MAX_VALUE.toLong().toUInt()).toInt()

    fun copy(
        r: Int = this.r,
        g: Int = this.g,
        b: Int = this.b,
        aOfOne: Float = this.aOfOne
    ) = HEXAColor(r = r, g = g, b = b, aOfOne = aOfOne)
    fun copy(
        r: Int = this.r,
        g: Int = this.g,
        b: Int = this.b,
        a: Int
    ) = HEXAColor(r = r, g = g, b = b, a = a)

    companion object {
        /**
         * Parsing color from [color]
         *
         * Supported formats samples (on Red color based):
         *
         * * `#f00`
         * * `#f00f`
         * * `#ff0000`
         * * `#ff0000ff`
         * * `rgb(255, 0, 0)`
         * * `rgba(255, 0, 0, 1)`
         */
        fun parseStringColor(color: String): HEXAColor = when {
            color.startsWith("#") -> color.removePrefix("#").let { color ->
                when (color.length) {
                    3 -> color.map { "$it$it" }.joinToString(separator = "", postfix = "ff")
                    4 -> color.take(3).map { "$it$it" }.joinToString(separator = "", postfix = color.takeLast(1).let { "${it}0" })
                    6 -> "${color}ff"
                    8 -> color
                    else -> error("Malfurmed color string: $color. It is expected that color started with # will contains 3, 6 or 8 valuable parts")
                }
            }
            color.startsWith("rgb(") -> color
                .removePrefix("rgb(")
                .removeSuffix(")")
                .replace(Regex("\\s"), "")
                .split(",")
                .joinToString("", postfix = "ff") {
                    it.toInt().toString(16).padStart(2, '0')
                }
            color.startsWith("rgba(") -> color
                .removePrefix("rgba(")
                .removeSuffix(")")
                .replace(Regex("\\s"), "")
                .split(",").let {
                    it.take(3).map { it.toInt().toString(16).padStart(2, '0') } + (it.last().toFloat() * 0xff).toInt().toString(16).padStart(2, '0')
                }
                .joinToString("")
            else -> color
        }.lowercase().toUInt(16).let(::HEXAColor)

        /**
         * Creates [HEXAColor] from [uint] presume it is in format `0xFFEEBBAA` where FF - red, EE - green, BB - blue` and AA - alpha
         */
        fun fromHexa(uint: UInt) = HEXAColor(uint)

        /**
         * Creates [HEXAColor] from [uint] presume it is in format `0xAAFFEEBB` where AA - alpha, FF - red, EE - green and BB - blue`
         */
        fun fromAhex(uint: UInt) = HEXAColor(
            a = ((uint and 0xff000000u) / 0x1000000u).toInt(),
            r = ((uint and 0x00ff0000u) / 0x10000u).toInt(),
            g = ((uint and 0x0000ff00u) / 0x100u).toInt(),
            b = ((uint and 0x000000ffu)).toInt()
        )

        /**
         * Parsing color from [color]
         *
         * Supported formats samples (on Red color based):
         *
         * * `#f00`
         * * `#ff0000`
         * * `#ff0000ff`
         * * `rgb(255, 0, 0)`
         * * `rgba(255, 0, 0, 1)`
         */
        operator fun invoke(color: String) = parseStringColor(color)

        private fun Int.shortPart(): String {
            return (floor(toFloat() / 16)).toInt().toString(16)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy