danmichaelo/coma
CoMa is a PHP color math library for converting between sRGB, XYZ and Lab color spaces and computing color difference (Delta E) metrics. Includes CIE76 and CIE94, with more planned. Suitable for matching and comparing colors.
Install the Package:
composer require danmichaelo/coma
Ensure autoloading is configured in composer.json:
"autoload": {
"psr-4": {
"Danmichaelo\\Coma\\": "vendor/danmichaelo/coma/src/"
}
}
Run composer dump-autoload.
First Use Case: Compare Two Colors Use CIE94 to measure perceptual difference between two sRGB colors:
use Danmichaelo\Coma\{sRGB, ColorDistance};
$primary = new sRGB(0, 128, 255); // Blue
$secondary = new sRGB(0, 100, 230); // Lighter blue
$distance = (new ColorDistance())->cie94($primary, $secondary);
echo "CIE94 ΔE: " . $distance; // Outputs ~15.3 (perceptual difference)
Convert Colors for Analysis Convert sRGB to Lab space (perceptually uniform) for accurate comparisons:
$labColor = $primary->toLab();
echo "L*: " . $labColor->L() . ", a*: " . $labColor->a() . ", b*: " . $labColor->b();
Integrate with Laravel Services Wrap the package in a Laravel service for reusability:
namespace App\Services;
use Danmichaelo\Coma\{sRGB, ColorDistance};
class ColorService
{
public function getDeltaE(string $hex1, string $hex2, string $metric = 'cie94'): float
{
$rgb1 = $this->hexToRgb($hex1);
$rgb2 = $this->hexToRgb($hex2);
$color1 = new sRGB($rgb1['r'], $rgb1['g'], $rgb1['b']);
$color2 = new sRGB($rgb2['r'], $rgb2['g'], $rgb2['b']);
return (new ColorDistance())->$metric($color1, $color2);
}
private function hexToRgb(string $hex): array
{
// Implement hex-to-RGB conversion
}
}
Use the package to convert between color spaces for analysis or storage:
// Convert sRGB to Lab (perceptually uniform for delta-E calculations)
$labColor = (new sRGB(255, 165, 0))->toLab();
// Convert Lab back to sRGB
$srgbFromLab = (new \Danmichaelo\Coma\Lab($labColor->L(), $labColor->a(), $labColor->b()))->toSRGB();
Enforce color consistency rules (e.g., design system compliance):
class ColorValidator
{
public function isWithinThreshold(sRGB $color, sRGB $reference, float $maxDeltaE = 5.0, string $metric = 'cie94'): bool
{
$distance = (new ColorDistance())->$metric($color, $reference);
return $distance <= $maxDeltaE;
}
}
Audit color consistency in assets (e.g., images, UI components):
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Danmichaelo\Coma\{sRGB, ColorDistance};
class AuditColors extends Command
{
protected $signature = 'colors:audit {--threshold=5}';
protected $description = 'Audit color consistency against a reference palette';
public function handle()
{
$reference = new sRGB(0, 128, 255); // Brand blue
$threshold = $this->option('threshold');
foreach ($this->getColorsToAudit() as $colorHex) {
$color = new sRGB(...hexToRgb($colorHex));
$distance = (new ColorDistance())->cie94($color, $reference);
$this->line(
sprintf(
"Color %s: ΔE %.2f %s",
$color->toHex(),
$distance,
$distance <= $threshold ? "✅ PASS" : "❌ FAIL"
)
);
}
}
}
Adjust UI colors dynamically while maintaining perceptual consistency:
class ThemeService
{
public function adjustColorForAccessibility(sRGB $baseColor, float $targetLuminance = 70.0): sRGB
{
$lab = $baseColor->toLab();
$adjustedLab = new \Danmichaelo\Coma\Lab($targetLuminance, $lab->a(), $lab->b());
return $adjustedLab->toSRGB();
}
}
Store and compare colors in a database:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Danmichaelo\Coma\sRGB;
class Product extends Model
{
protected $casts = [
'color_hex' => 'string',
];
public function getColorAttribute(): sRGB
{
return new sRGB(...hexToRgb($this->color_hex));
}
public function isColorSimilarTo(Product $other, float $threshold = 10.0): bool
{
$distance = (new \Danmichaelo\Coma\ColorDistance())->cie94($this->color, $other->color);
return $distance <= $threshold;
}
}
Return delta-E results in API responses for client-side validation:
use App\Services\ColorService;
Route::get('/api/colors/compare', function (ColorService $colorService) {
$hex1 = request('hex1');
$hex2 = request('hex2');
$deltaE = $colorService->getDeltaE($hex1, $hex2);
return response()->json([
'delta_e' => $deltaE,
'passes_threshold' => $deltaE <= 5.0,
'colors' => [
'hex1' => $hex1,
'hex2' => $hex2,
],
]);
});
RGB Value Range:
sRGB(256, 0, 0)) will cause incorrect conversions.if ($r < 0 || $r > 255 || $g < 0 || $g > 255 || $b < 0 || $b > 255) {
throw new \InvalidArgumentException("RGB values must be 0-255");
}
Floating-Point Precision:
$distance = round((new ColorDistance())->cie94($color1, $color2), 2);
Color Space Assumptions:
No CIEDE2000:
Limited Documentation:
Log Color Conversions:
$lab = $srgb->toLab();
\Log::debug('Color conversion', [
'sRGB' => $srgb->toArray(),
'Lab' => [$lab->L(), $lab->a(), $lab->b()],
]);
Validate Against Known Values: Compare results with online calculators or test vectors:
// Known test case: Delta-E between black (0,0,0) and white (255,255,255) should be ~100 in CIE76
How can I help you explore Laravel packages today?