From 9242c6a76571b083fdc5fde493403f3f438eb77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=9D=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=BC=D0=BE=D0=B2?= Date: Fri, 6 Jun 2025 03:17:18 +0300 Subject: [PATCH] Fix and improve parse color function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now this function supports multiple hex color formats with optional hash prefix: 3 digits (RGB): Each digit is expanded to two digits (e.g., "F0A" → "FF00AA") 4 digits (ARGB): Each digit is expanded to two digits (e.g., "8F0A" → "88FF00AA") 6 digits (RRGGBB): Standard RGB format with full alpha (255) 8 digits (AARRGGBB): Full ARGB format with explicit alpha channel --- .../dev/icerock/moko/graphics/ColorHEX.kt | 74 +++++++++++++++---- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/graphics/src/commonMain/kotlin/dev/icerock/moko/graphics/ColorHEX.kt b/graphics/src/commonMain/kotlin/dev/icerock/moko/graphics/ColorHEX.kt index 0487719..b9c2a99 100644 --- a/graphics/src/commonMain/kotlin/dev/icerock/moko/graphics/ColorHEX.kt +++ b/graphics/src/commonMain/kotlin/dev/icerock/moko/graphics/ColorHEX.kt @@ -4,21 +4,67 @@ package dev.icerock.moko.graphics +/** + * Parses a hexadecimal color string into a [Color] object. + * + * This function supports multiple hex color formats with optional hash prefix: + * - **3 digits (RGB)**: Each digit is expanded to two digits (e.g., "F0A" → "FF00AA") + * - **4 digits (ARGB)**: Each digit is expanded to two digits (e.g., "8F0A" → "88FF00AA") + * - **6 digits (RRGGBB)**: Standard RGB format with full alpha (255) + * - **8 digits (AARRGGBB)**: Full ARGB format with explicit alpha channel + * + * The hash prefix (#) is optional and will be automatically removed if present. + * All input is converted to uppercase for consistent parsing. + * + * @param colorHEX + * The hexadecimal color string to parse. Can include optional '#' prefix. + * Supports formats: RGB, ARGB, RRGGBB, AARRGGBB (case-insensitive). + * + * @return A [Color] object with ARGB values in the range 0-255. + * + * @throws IllegalArgumentException + * if the input string is not a valid hex color format or contains invalid hexadecimal characters. + * + */ @Suppress("MagicNumber") -fun Color.Companion.parseColor(colorHEX: String): Color { - require(colorHEX[0] != '#') { "Unknown color" } +public fun Color.Companion.parseColor(colorHEX: String): Color { + val clean = colorHEX.removePrefix("#").uppercase() - var colorARGB = colorHEX.substring(1).toLong(16) - if (colorHEX.length == 7) { - colorARGB = colorARGB or 0x00000000ff000000 - } else { - require(colorHEX.length != 9) { "Unknown color" } - } + return when (clean.length) { + 3 -> { + // RGB -> RRGGBB + val r = clean[0].digitToInt(16) * 17 + val g = clean[1].digitToInt(16) * 17 + val b = clean[2].digitToInt(16) * 17 + Color(red = r, green = g, blue = b, alpha = 255) + } + + 4 -> { + // ARGB + val a = clean[0].digitToInt(radix = 16) * 17 + val r = clean[1].digitToInt(16) * 17 + val g = clean[2].digitToInt(16) * 17 + val b = clean[3].digitToInt(16) * 17 + Color(alpha = a, red = r, green = g, blue = b) + } - return Color( - alpha = (colorARGB.shr(24) and 0xFF).toInt(), - red = (colorARGB.shr(16) and 0xFF).toInt(), - green = (colorARGB.shr(8) and 0xFF).toInt(), - blue = (colorARGB.shr(0) and 0xFF).toInt(), - ) + 6 -> { + // RRGGBB + val r = clean.substring(0, 2).toInt(16) + val g = clean.substring(2, 4).toInt(16) + val b = clean.substring(4, 6).toInt(16) + Color(red = r, green = g, blue = b, alpha = 255) + } + + 8 -> { + // AARRGGBB + val a = clean.substring(0, 2).toInt(16) + val r = clean.substring(2, 4).toInt(16) + val g = clean.substring(4, 6).toInt(16) + val b = clean.substring(6, 8).toInt(16) + Color(alpha = a, red = r, green = g, blue = b) + } + + else -> throw IllegalArgumentException("Invalid Hex color: $colorHEX") + } }