| 1 | <?php |
| 2 | // parse_colors.php |
| 3 | require_once 'functions.php'; |
| 4 | |
| 5 | function parseColor($color) { |
| 6 | if (strlen($color) > 100) { // prevent long inputs that might mess up the code |
| 7 | return false; |
| 8 | } |
| 9 | |
| 10 | // Add CSS color name mapping |
| 11 | $cssColors = [ |
| 12 | 'aliceblue' => [240, 248, 255], 'antiquewhite' => [250, 235, 215], 'aqua' => [0, 255, 255], 'aquamarine' => [127, 255, 212], 'azure' => [240, 255, 255], 'beige' => [245, 245, 220], 'bisque' => [255, 228, 196], 'black' => [0, 0, 0], 'blanchedalmond' => [255, 235, 205], 'blue' => [0, 0, 255], 'blueviolet' => [138, 43, 226], 'brown' => [165, 42, 42], 'burlywood' => [222, 184, 135], 'cadetblue' => [95, 158, 160], 'chartreuse' => [127, 255, 0], 'chocolate' => [210, 105, 30], 'coral' => [255, 127, 80], 'cornflowerblue' => [100, 149, 237], 'cornsilk' => [255, 248, 220], 'crimson' => [220, 20, 60], 'cyan' => [0, 255, 255], 'darkblue' => [0, 0, 139], 'darkcyan' => [0, 139, 139], 'darkgoldenrod' => [184, 134, 11], 'darkgray' => [169, 169, 169], 'darkgreen' => [0, 100, 0], 'darkgrey' => [169, 169, 169], 'darkkhaki' => [189, 183, 107], 'darkmagenta' => [139, 0, 139], 'darkolivegreen' => [85, 107, 47], 'darkorange' => [255, 140, 0], 'darkorchid' => [153, 50, 204], 'darkred' => [139, 0, 0], 'darksalmon' => [233, 150, 122], 'darkseagreen' => [143, 188, 143], 'darkslateblue' => [72, 61, 139], 'darkslategray' => [47, 79, 79], 'darkslategrey' => [47, 79, 79], 'darkturquoise' => [0, 206, 209], 'darkviolet' => [148, 0, 211], 'deeppink' => [255, 20, 147], 'deepskyblue' => [0, 191, 255], 'dimgray' => [105, 105, 105], 'dimgrey' => [105, 105, 105], 'dodgerblue' => [30, 144, 255], 'firebrick' => [178, 34, 34], 'floralwhite' => [255, 250, 240], 'forestgreen' => [34, 139, 34], 'fuchsia' => [255, 0, 255], 'gainsboro' => [220, 220, 220], 'ghostwhite' => [248, 248, 255], 'gold' => [255, 215, 0], 'goldenrod' => [218, 165, 32], 'gray' => [128, 128, 128], 'grey' => [128, 128, 128], 'green' => [0, 128, 0], 'greenyellow' => [173, 255, 47], 'honeydew' => [240, 255, 240], 'hotpink' => [255, 105, 180], 'indianred' => [205, 92, 92], 'indigo' => [75, 0, 130], 'ivory' => [255, 255, 240], 'khaki' => [240, 230, 140], 'lavender' => [230, 230, 250], 'lavenderblush' => [255, 240, 245], 'lawngreen' => [124, 252, 0], 'lemonchiffon' => [255, 250, 205], 'lightblue' => [173, 216, 230], 'lightcoral' => [240, 128, 128], 'lightcyan' => [224, 255, 255], 'lightgoldenrodyellow' => [250, 250, 210], 'lightgray' => [211, 211, 211], 'lightgreen' => [144, 238, 144], 'lightgrey' => [211, 211, 211], 'lightpink' => [255, 182, 193], 'lightsalmon' => [255, 160, 122], 'lightseagreen' => [32, 178, 170], 'lightskyblue' => [135, 206, 250], 'lightslategray' => [119, 136, 153], 'lightslategrey' => [119, 136, 153], 'lightsteelblue' => [176, 196, 222], 'lightyellow' => [255, 255, 224], 'lime' => [0, 255, 0], 'limegreen' => [50, 205, 50], 'linen' => [250, 240, 230], 'magenta' => [255, 0, 255], 'maroon' => [128, 0, 0], 'mediumaquamarine' => [102, 205, 170], 'mediumblue' => [0, 0, 205], 'mediumorchid' => [186, 85, 211], 'mediumpurple' => [147, 112, 219], 'mediumseagreen' => [60, 179, 113], 'mediumslateblue' => [123, 104, 238], 'mediumspringgreen' => [0, 250, 154], 'mediumturquoise' => [72, 209, 204], 'mediumvioletred' => [199, 21, 133], 'midnightblue' => [25, 25, 112], 'mintcream' => [245, 255, 250], 'mistyrose' => [255, 228, 225], 'moccasin' => [255, 228, 181], 'navajowhite' => [255, 222, 173], 'navy' => [0, 0, 128], 'oldlace' => [253, 245, 230], 'olive' => [128, 128, 0], 'olivedrab' => [107, 142, 35], 'orange' => [255, 165, 0], 'orangered' => [255, 69, 0], 'orchid' => [218, 112, 214], 'palegoldenrod' => [238, 232, 170], 'palegreen' => [152, 251, 152], 'paleturquoise' => [175, 238, 238], 'palevioletred' => [219, 112, 147], 'papayawhip' => [255, 239, 213], 'peachpuff' => [255, 218, 185], 'peru' => [205, 133, 63], 'pink' => [255, 192, 203], 'plum' => [221, 160, 221], 'powderblue' => [176, 224, 230], 'purple' => [128, 0, 128], 'rebeccapurple' => [102, 51, 153], 'red' => [255, 0, 0], 'rosybrown' => [188, 143, 143], 'royalblue' => [65, 105, 225], 'saddlebrown' => [139, 69, 19], 'salmon' => [250, 128, 114], 'sandybrown' => [244, 164, 96], 'seagreen' => [46, 139, 87], 'seashell' => [255, 245, 238], 'sienna' => [160, 82, 45], 'silver' => [192, 192, 192], 'skyblue' => [135, 206, 235], 'slateblue' => [106, 90, 205], 'slategray' => [112, 128, 144], 'slategrey' => [112, 128, 144], 'snow' => [255, 250, 250], 'springgreen' => [0, 255, 127], 'steelblue' => [70, 130, 180], 'tan' => [210, 180, 140], 'teal' => [0, 128, 128], 'thistle' => [216, 191, 216], 'tomato' => [255, 99, 71], 'turquoise' => [64, 224, 208], 'violet' => [238, 130, 238], 'wheat' => [245, 222, 179], 'white' => [255, 255, 255], 'whitesmoke' => [245, 245, 245], 'yellow' => [255, 255, 0], 'yellowgreen' => [154, 205, 50] |
| 13 | ]; |
| 14 | |
| 15 | // Remove multiline comments |
| 16 | $color = preg_replace('/\/\*.*?\*\//s', '', $color); |
| 17 | // Remove inline comments until newline or semicolon |
| 18 | $color = preg_replace('/\/\/[^;\n]*[;\n]/', '', $color); |
| 19 | // Strip // comments |
| 20 | $color = preg_replace('|//.*$|m', '', $color); |
| 21 | |
| 22 | // Extract everything after the last colon, handling both CSS properties and variables |
| 23 | if (preg_match('/^.*:\s*(.+)$/', $color, $matches)) { |
| 24 | $color = $matches[1]; |
| 25 | } |
| 26 | |
| 27 | // Strip any remaining CSS syntax or semicolons |
| 28 | $color = preg_replace('/;+.*/', '', $color); // Remove multiple semicolons and anything after |
| 29 | $color = preg_replace('/}.*/', '', $color); // Remove closing brace and anything after |
| 30 | $color = strtolower(trim($color)); // Normalize to lowercase |
| 31 | |
| 32 | // Check if it's a named CSS color |
| 33 | if (isset($cssColors[$color])) { |
| 34 | return array_merge($cssColors[$color], [1]); // Add alpha = 1 for named colors |
| 35 | } |
| 36 | |
| 37 | // Validate hex format length before processing |
| 38 | if (preg_match('/^#?[A-Fa-f0-9]+$/', $color) && strlen(ltrim($color, '#')) != 3 && strlen(ltrim($color, '#')) != 4 && strlen(ltrim($color, '#')) != 6 && strlen(ltrim($color, '#')) != 8) { |
| 39 | return false; |
| 40 | } |
| 41 | |
| 42 | // Process valid hex colors |
| 43 | if (preg_match('/^#?([A-Fa-f0-9]{3,8})$/', $color, $matches)) { |
| 44 | $hex = ltrim($color, '#'); |
| 45 | $length = strlen($hex); |
| 46 | |
| 47 | switch($length) { |
| 48 | case 3: // #RGB |
| 49 | $r = hexdec($hex[0].$hex[0]); |
| 50 | $g = hexdec($hex[1].$hex[1]); |
| 51 | $b = hexdec($hex[2].$hex[2]); |
| 52 | return [$r, $g, $b, 1]; |
| 53 | case 4: // #RGBA |
| 54 | $r = hexdec($hex[0].$hex[0]); |
| 55 | $g = hexdec($hex[1].$hex[1]); |
| 56 | $b = hexdec($hex[2].$hex[2]); |
| 57 | $a = hexdec($hex[3].$hex[3]) / 255; |
| 58 | return [$r, $g, $b, $a]; |
| 59 | case 6: // #RRGGBB |
| 60 | $r = hexdec(substr($hex, 0, 2)); |
| 61 | $g = hexdec(substr($hex, 2, 2)); |
| 62 | $b = hexdec(substr($hex, 4, 2)); |
| 63 | return [$r, $g, $b, 1]; |
| 64 | case 8: // #RRGGBBAA |
| 65 | $r = hexdec(substr($hex, 0, 2)); |
| 66 | $g = hexdec(substr($hex, 2, 2)); |
| 67 | $b = hexdec(substr($hex, 4, 2)); |
| 68 | $a = hexdec(substr($hex, 6, 2)) / 255; |
| 69 | return [$r, $g, $b, $a]; |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | if (preg_match('/^cmyk\((\d+)%?,\s*(\d+)%?,\s*(\d+)%?,\s*(\d+)%?\)$/', $color, $matches)) { |
| 74 | return cmykToRgb( |
| 75 | floatval($matches[1]), |
| 76 | floatval($matches[2]), |
| 77 | floatval($matches[3]), |
| 78 | floatval($matches[4]) |
| 79 | ); |
| 80 | } elseif (preg_match('/^rgba?\(\s*([\d.]+)(?:\s+|\s*,\s*)([\d.]+)(?:\s+|\s*,\s*)([\d.]+)(?:\s*(?:\/|\s*,)\s*([\d.]+%?))?\s*\)$/', $color, $matches)) { |
| 81 | $alpha = isset($matches[4]) ? (str_ends_with($matches[4], '%') ? |
| 82 | floatval(rtrim($matches[4], '%')) / 100 : |
| 83 | floatval($matches[4])) : 1; |
| 84 | $rgb = [ |
| 85 | intval(floatval($matches[1])), |
| 86 | intval(floatval($matches[2])), |
| 87 | intval(floatval($matches[3])) |
| 88 | ]; |
| 89 | return array_merge($rgb, [$alpha]); |
| 90 | } elseif (preg_match('/^hsla?\(\s*([\d.]+)(?:deg|turn)?(?:(?:\s+|\s*,\s*)|\s+)(\d+\.?\d*)%(?:\s+|\s*,\s*)(\d+\.?\d*)%(?:\s*(?:\/|\s*,)\s*([\d.]+%?))?\s*\)$/', $color, $matches)) { |
| 91 | $alpha = isset($matches[4]) ? (str_ends_with($matches[4], '%') ? |
| 92 | floatval(rtrim($matches[4], '%')) / 100 : |
| 93 | floatval($matches[4])) : 1; |
| 94 | $rgb = hslToRgb($matches[1], floatval($matches[2]), floatval($matches[3])); |
| 95 | return array_merge($rgb, [$alpha]); |
| 96 | } elseif (preg_match('/^lab\(\s*(\d+\.?\d*)%?\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)(?:\s*\/\s*([\d.]+))?\s*\)$/', $color, $matches)) { |
| 97 | return array_merge(labToRgb( |
| 98 | floatval($matches[1]), |
| 99 | floatval($matches[2]), |
| 100 | floatval($matches[3]) |
| 101 | ), [isset($matches[4]) ? floatval($matches[4]) : 1]); |
| 102 | } elseif (preg_match('/^hsb\((\d+),\s*(\d+)%?,\s*(\d+)%?\)$/', $color, $matches)) { |
| 103 | return hsbToRgb( |
| 104 | floatval($matches[1]), |
| 105 | floatval($matches[2]), |
| 106 | floatval($matches[3]) |
| 107 | ); |
| 108 | } elseif (preg_match('/^hwb\(\s*([\d.]+)(deg|turn)?\s+(\d+(?:\.\d+)?%)\s+(\d+(?:\.\d+)?%)(?:\s*(?:\/|,)\s*([\d.]+%?))?\s*\)$/', $color, $matches)) { |
| 109 | // Convert turn to degrees if specified |
| 110 | $hue = floatval($matches[1]); |
| 111 | if (isset($matches[2]) && $matches[2] === 'turn') { |
| 112 | $hue *= 360; |
| 113 | } |
| 114 | |
| 115 | // Extract whiteness and blackness percentages |
| 116 | $whiteness = floatval(rtrim($matches[3], '%')); |
| 117 | $blackness = floatval(rtrim($matches[4], '%')); |
| 118 | |
| 119 | // Handle alpha value |
| 120 | $alpha = 1; |
| 121 | if (isset($matches[5])) { |
| 122 | $alpha = str_ends_with($matches[5], '%') ? |
| 123 | floatval(rtrim($matches[5], '%')) / 100 : |
| 124 | floatval($matches[5]); |
| 125 | } |
| 126 | |
| 127 | $rgb = hwbToRgb($hue, $whiteness, $blackness); |
| 128 | return array_merge($rgb, [$alpha]); |
| 129 | } elseif (preg_match('/^lch\(\s*(\d*\.?\d+)%?\s+(\d*\.?\d+)\s+(\d*\.?\d+)(?:\s*\/\s*([\d.]+))?\s*\)$/', $color, $matches)) { |
| 130 | // Extract values |
| 131 | $lightness = floatval($matches[1]); |
| 132 | $chroma = floatval($matches[2]); |
| 133 | $hue = floatval($matches[3]); |
| 134 | $alpha = isset($matches[4]) ? floatval($matches[4]) : 1; |
| 135 | |
| 136 | // If lightness wasn't specified with %, scale it to 0-100 range if it's in 0-1 range |
| 137 | if (strpos($matches[1], '%') === false && $lightness <= 1) { |
| 138 | $lightness *= 100; |
| 139 | } |
| 140 | |
| 141 | $rgb = lchToRgb($lightness, $chroma, $hue, $alpha); |
| 142 | return $rgb; |
| 143 | } elseif (preg_match('/^oklab\(\s*(\d*\.?\d+)%?\s+(-?\d*\.?\d+)\s+(-?\d*\.?\d+)(?:\s*\/\s*([\d.]+))?\s*\)$/', $color, $matches)) { |
| 144 | // Extract values |
| 145 | $lightness = floatval($matches[1]); |
| 146 | $a = floatval($matches[2]); |
| 147 | $b = floatval($matches[3]); |
| 148 | $alpha = isset($matches[4]) ? floatval($matches[4]) : 1; |
| 149 | |
| 150 | // If lightness wasn't specified with %, scale it to 0-100 range if it's in 0-1 range |
| 151 | if (strpos($matches[1], '%') === false && $lightness <= 1) { |
| 152 | $lightness *= 100; |
| 153 | } |
| 154 | // Convert to 0-1 range |
| 155 | $lightness = $lightness / 100; |
| 156 | |
| 157 | return oklabToRgb($lightness, $a, $b, $alpha); |
| 158 | |
| 159 | } elseif (preg_match('/^oklch\(\s*(\d*\.?\d+)%?\s+(\d*\.?\d+)\s+(\d*\.?\d+)(?:\s*\/\s*([\d.]+%?))?\s*\)$/i', $color, $matches)) { |
| 160 | // Extract values |
| 161 | $lightness = floatval($matches[1]); |
| 162 | $chroma = floatval($matches[2]); |
| 163 | $hue = floatval($matches[3]); |
| 164 | |
| 165 | // Handle alpha: may be null, a number, or a percentage |
| 166 | $alpha = 1; |
| 167 | if (isset($matches[4])) { |
| 168 | $alphaStr = $matches[4]; |
| 169 | if (str_ends_with($alphaStr, '%')) { |
| 170 | $alpha = floatval(rtrim($alphaStr, '%')) / 100; |
| 171 | } else { |
| 172 | $alpha = floatval($alphaStr); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | // If lightness wasn't specified with %, scale it to 0–100 if it’s ≤ 1 |
| 177 | if (strpos($matches[1], '%') === false && $lightness <= 1) { |
| 178 | $lightness *= 100; |
| 179 | } |
| 180 | |
| 181 | // Normalize to 0–1 |
| 182 | $lightness = $lightness / 100; |
| 183 | |
| 184 | return oklchToRgb($lightness, $chroma, $hue, $alpha); |
| 185 | } |
| 186 | |
| 187 | return false; |
| 188 | } |
| 189 | ?> |