https://github.com/atomicptr/color
Couleur is a modern PHP 8.1+ color library, intended to be compatible with CSS Color Module Level 4.
https://github.com/atomicptr/color
Last synced: 3 months ago
JSON representation
Couleur is a modern PHP 8.1+ color library, intended to be compatible with CSS Color Module Level 4.
- Host: GitHub
- URL: https://github.com/atomicptr/color
- Owner: atomicptr
- License: mit
- Created: 2025-02-06T12:38:59.000Z (12 months ago)
- Default Branch: master
- Last Pushed: 2025-02-06T16:23:16.000Z (12 months ago)
- Last Synced: 2025-02-16T09:57:31.913Z (12 months ago)
- Language: PHP
- Homepage:
- Size: 188 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 🎨 Color: A modern PHP 8.3+ color library
[](https://github.com/atomicptr/color/blob/main/LICENSE)
[](https://packagist.org/packages/atomicptr/color)
[](https://github.com/atomicptr/color)
[](https://packagist.org/packages/atomicptr/color)
[](https://packagist.org/packages/atomicptr/color)
**Color** is a modern **PHP 8.3+ color library**, intended to be compatible with **[CSS Color Module Level 4](https://drafts.csswg.org/css-color-4)**, and inspired by **[Color.js](https://github.com/LeaVerou/color.js)** from [Lea Verou](https://github.com/LeaVerou) and [Chris Lilley](https://github.com/svgeesus).
This is a hard fork of [matthieumastadenis/couleur](https://github.com/matthieumastadenis/couleur)
The main goal of this package is to allow **color conversions** between multiple, old and new [🌈 Color Spaces](#-color-spaces), like the famous **LCH** which provides [many advantages for design purpose](https://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/).
**Color** is made to be usable with an **[OOP](https://en.wikipedia.org/wiki/Object-oriented_programming)** approach as well as with a **[FP](https://en.wikipedia.org/wiki/Functional_programming)** approach:
- If you prefer **OOP**, you can use [🏭 Immutable Objects and the `ColorFactory`](#-immutable-objects-and-the-colorfactory) ;
- If you prefer **FP**, you can directly use the multiple [🧰 Pure Functions](#-pure-functions) ;
## ⚙️ Installation
Use the following command to add **Color** to your project with [Composer](https://getcomposer.org/):
```bash
composer require atomicptr/color
```
Don't forget to include the [autoloader](https://getcomposer.org/doc/01-basic-usage.md#autoloading) provided by Composer:
```php
toRgb();
// Stringify:
echo $rgb1; // Prints 'rgb(100% 0% 0%)'
echo $rgb1->stringify(); // Prints 'rgb(100% 0% 0%)'
echo $rgb1->stringify(legacy : false, alpha : true); // Prints 'rgb(100% 0% 0% / 100%)'
echo $rgb1->stringify(legacy : true); // Prints 'rgb(255,0,0)'
echo $rgb1->stringify(legacy : true, alpha : true); // Prints 'rgba(255,0,0,1)'
// Create a variant color:
$rgb2 = $rgb1->change('-35', '+20', 60);
echo $rgb2->stringify(legacy : true); // Prints 'rgb(220,20,60)';
// Convert to CSS:
$css2 = $rgb2->toCss();
echo $css2; // Prints 'crimson'
// Convert to Lch:
$lch = $css2->toLch();
echo $lch->stringify(alpha : true); // Prints 'lch(47.878646049% 79.619059282 26.464486652deg / 100%)'
// Convert to P3:
$p3 = $lch->toP3();
echo $p3; // Prints 'color(display-p3 0.791710722 0.191507424 0.257366748)'
```
[↑ Back to Top](#-color-a-modern-php-83-color-library)
## 📚 Usage
### 🏭 Immutable Objects and the `ColorFactory`
#### Direct instanciation
**Color** provides one **immutable class** for each supported [🌈 Color Space](#-color-spaces). You can of course instantiate these classes manually:
```php
**Note** :
> You may have noticed from the previous example that it implies passing *correctly formatted* values to each constructor.
>
> For example, the `Rgb` class expects to receive opacity expressed in the same magnitude than red, green and blue values, meaning *as a number between 0 and 255*. Same thing for the `HexRgb` class which expects only *hexadecimal strings* for each of the four parameters it takes (opacity included).
>
> Because of this, you may prefer to avoid instanciating these classes yourself. A simpler solution is to [use the ColorFactory](#using-the-colorfactory) like in the following examples. It will automatically handle *values conversion* for you.
[↑ Back to Top](#-color-a-modern-php-83-color-library)
#### Using the `ColorFactory`
The best and simplest way to create color objects is by using the `ColorFactory` **abstract class** which provides a specific **static method** for each supported [🌈 Color Space](#-color-spaces):
```php
coordinates()); // [ 0, 100, 50, 255 ]
// With the $from parameter, we can ensure that the input value will be treated like we want
// The following line creates a new colors\Rgb instance from an HSL input:
$rgb2 = ColorFactory::newRgb([ 0, 100, 50 ], 'hsl');
\var_dump($rgb2->coordinates()); // [ 255, 0, 0, 255 ]
// Same result, but with usage of the ColorSpace enum:
$rgb3 = ColorFactory::newRgb([ 0, 100, 50 ], ColorSpace::Hsl);
\var_dump($rgb3->coordinates()); // [ 255, 0, 0, 255 ]
```
You can alternatively use the `new()` **static method**, which adds a `$to` parameter just after the input value. If this parameter is not specified, the *targetted color space* will automatically be determined according to the format of the value:
```php
toCss();
// Converting to a new colors\XyzD50 instance:
$xyzD50 = $css->toXyzD50();
// Converting to a new colors\OkLch instance (using the to() method):
$okLch = $xyzD50->to(ColorSpace::OkLch);
```
Note that **any color** can be converted to CSS with the `toCss()` method. It will automatically pick the *closest* CSS color:
```php
toCss();
// Prints 'red':
echo $css;
```
All color objects are directly **stringable**. They also provide a `stringify()` method which offers more possibilities:
```php
stringify(null, true);
// Prints 'rgba(255,0,0,1)' (using $legacy and $alpha parameters):
echo $rgb->stringify(true, true);
$lch = ColorFactory::newLch([ 54.2905429, 106.837191, 40.8576688 ], ColorSpace::Lch);
// Prints 'lch(54.29% 106.84 40.86deg)' Using the $precision parameter:
echo $lch->stringify(precision : 2);
```
All color objects also have a `coordinates()` method which returns an array:
```php
coordinates();
```
You can also directly access **readonly properties** from each color object:
```php
red;
$hsl = ColorFactory::newHsl([ 0, 100, 50 ]);
// Prints 50:
echo $hsl->lightness;
```
All color objects have a `change()` method which always return a *new object* corresponding to a *variant* of the current color.
```php
change(hue : 180, opacity : 80);
echo $hsl2; // hsl(180deg 100% 50% / 80%)
// Add, subtract, multiply, divide coordinates:
$hsl3 = $hsl2->change('+20', '-10', '*1.5', '/2');
echo $hsl3; // hsl(200deg 90% 75% / 40%)
// Reduce coordinates by modulus:
$hsl4 = $hsl3->change(opacity : '%6');
echo $hsl4; // hsl(200deg 90% 75% / 4%)
// Calculate the percentage of coordinates:
$hsl5 = $hsl4->change('50%');
echo $hsl5; // hsl(100deg 90% 75% / 4%)
// Add, subtract, multiply, divide coordinates by a percentage:
$hsl6 = $hsl5->change('+50%', '-50%', '/10%', '*200%');
echo $hsl6; // hsl(150deg 45% 10% / 32%)
// Reduce coordinates by a percentage modulus:
$hsl7 = $hsl6->change(saturation : '%20%');
echo $hsl7; // hsl(150deg 0% 10% / 32%)
```
> **Note**:
> The `change()` method of the `HexRgb` class behave differently depending on the operation you ask for :
>
> - For replacing a coordinate you have to provide an **hexadecimal value** ;
> - For additions and substractions you have to provide an **hexadecimal value** ;
> - For all other operactions you have to provide a **decimal value** ;
>
> Please observe the detailed demonstration in the next example:
```php
change('80', 'AA', 'BB', 'AA');
echo $hex2; // #80AABBAA
// When adding or subtracting coordinates, provide hexadecimal numbers:
$hex3 = $hex2->change('+8', '-11');
echo $hex3; // #89BA (88 99 BB AA)
// When multiplying, dividing or reducing coordinates by modulo, provide decimal numbers:
$hex4 = $hex3->change(null, '*1.5', '/2', '%3');
echo $hex4; // #88E65E02 (88 dechex(153*1.5) dechex(187/2) dechex(170%3))
// When using percentages, provide decimal numbers:
$hex5 = $hex4->change('20%');
echo $hex5; // #1BE65E02 (dechex(136*20/100) E6 5E 02)
// When using percentages with addition, substraction, multiplication or division, provide decimal numbers:
$hex6 = $hex5->change('+50%', '-20%', '/2%', '*200%');
echo $hex6; // #29B83208 (dechex(27+(27*50/100)) dechex(230-(230*20/100)) dechex(94/(84*2/100)) dechex(2*(2*200/100)))
// When using percentages with modulo, provide decimal numbers:
$hex7 = $hex6->change(green : '%4%');
echo $hex7; // #29023208 (29 dechex(184%(184*4/100)) 32 08)
```
> **Note**:
> The `change()` method of the `Css` class also behave differently: it only accepts a stringable color name or an instances of [the CssColor Enum](#the-csscolor-enum), which replace the color without variations.
>
> Please observe the next example:
```php
change(CssColor::purple);
echo $css2; // purple
$css2 = $css1->change(CssColor::purple);
echo $css2; // purple
$css3 = $css2->change('hotpink');
echo $css3; // hotpink
// Throws an UnsupportedCssColor Exception:
$css4 = $css3->change('invalid');
```
[↑ Back to Top](#-color-a-modern-php-83-color-library)
### 🧰 Pure Functions
Objects in **Color** are all based on a collection of **pure functions** under the hood. These functions can be used directly if you don't want to use objects.
> **Note**:
> Choosing this *functional programming approach* is better in terms of performance, but can be a bit more tedious because you have to manipulate arrays of values instead of objects.
There are three main types of functions provided by **Color** : dedicated [Color Space Functions](#color-space-functions), dedicated [Conversion Functions](#conversion-functions), and [Generic Functions](#generic-functions):
#### Color Space Functions
Each supported [🌈 Color Space](#-color-spaces) has its own dedicated functions, accessible under the namespace `Atomicptr\Color\Utils\[space]`. Those are the same for each color space: `clean()`, `from()`, `stringify()` and `verify()`.
`clean()` functions are made to transform an input value in a correctly formated set of values, according to the corresponding color space. They all return an array, except for `css\clean()` which directly returns an instance of the [the `CssColor` Enum](#the-csscolor-enum):
```php
**Note** :
> This function does not *clean* values inside of the array. For a typical usage, you may want to pass its result into the corresponding `clean()` function (see the [Color Space Functions](#color-space-functions) section for more details).
```php
value;
// Always returns 9, which is the default value for the COULEUR_PRECISION constant:
Constant::PRECISION->value;
// Returns the value of the COULEUR_LEGACY constant if defined, or 0 by default:
Constant::LEGACY->value();
// Returns the value of the COULEUR_PRECISION constant if defined, or 9 by default:
Constant::PRECISION->value();
// Returns the value of the COULEUR_LEGACY constant if defined, or 1 as fallback:
Constant::LEGACY->value(1);
// Returns the value of the COULEUR_PRECISION constant if defined, or 3 as fallback:
Constant::PRECISION->value(3);
// Returns the value of the COULEUR_LEGACY constant if defined, or define it with 1 as value then returns 1:
Constant::LEGACY->value(1, true);
// Returns the value of the COULEUR_PRECISION constant if defined, or define it with 3 as value then returns 3:
Constant::PRECISION->value(3, true);
```
[↑ Back to Top](#-color-a-modern-php-83-color-library)
#### The `ColorSpace` Enum
This enum is the simplest way to access all **color spaces** supported by **Color**:
```php
aliases();
// Returns ColorSpace::Rgb:
ColorSpace::fromAlias('rgb');
ColorSpace::fromAlias('srgb');
ColorSpace::fromAlias('RGBA');
// Returns ColorSpace::Lab:
ColorSpace::fromAlias('lab');
ColorSpace::fromAlias('cielab');
ColorSpace::fromAlias('CIE-LAB');
```
You can easily access [dedicated functions](#color-space-functions) from each `ColorSpace` with the `cleanCallback()`, `fromCallback()`, `stringifyCallback()` and `verifyCallback()` methods:
```php
cleanCallback();
// Returns [ 255, 127.5, 0, 255 ]:
ColorSpace::Rgb->cleanCallback()('rgb(100%,50%,0)');
// Returns [ 'FF', '00', '00', 'FF' ]:
ColorSpace::HexRgb->cleanCallback()('#f00');
// Returns 'Atomicptr\Color\Utils\XyzD50\from':
ColorSpace::XyzD50->fromCallback();
// Returns [ 255, 0, 0, 255 ]:
ColorSpace::Rgb->fromCallback()('hsl(0deg,100%,50%)');
// Returns CssColor::red:
ColorSpace::Css->fromCallback()('#f00');
// Returns 'Atomicptr\Color\Utils\XyzD50\stringify':
ColorSpace::XyzD50->stringifyCallback();
// Returns 'rgb(100% 0% 0% / 50%):
ColorSpace::Rgb->stringifyCallback()(255, 0 , 0, 127.5);
// Returns '#F00':
ColorSpace::Css->stringifyCallback()(CssColor::red);
// Returns 'Atomicptr\Color\Utils\CSS\verify':
ColorSpace::Css->verifyCallback();
// Returns true:
ColorSpace::Rgb->verifyCallback()('rgb(100%,50%,0)');
// Returns false:
ColorSpace::HexRgb->verifyCallback()('#ff');
```
[↑ Back to Top](#-color-a-modern-php-83-color-library)
#### The `CssColor` Enum
This enum helps managing `CSS` **named colors**. With its multiple methods, you can easily know if a `CssColor` exists and get the corresponding `RGB` or `HexRGB` coordinates from it:
```php
toRgbCoordinates();
// Returns [ 'FF', '00', '00' ]:
CssColor::red->toHexRgbCoordinates();
```
The `fromCss()` method allows you to get a specific `CssColor` by its name. If no supported color matches the `$name` parameter, a `UnsupportedCssColor` Exception will be thrown by default, unless you provide a `$fallback` or you set the `$throw` parameter to **false**.
```php
toHexRgbString();
// Returns '#f00' (using the $uppercase parameter):
CssColor::red->toHexRgbString(uppercase : false);
// Returns 'F00' (using the $sharp parameter):
CssColor::red->toHexRgbString(sharp : false);
// Returns '#F00F' (using the $alpha parameter):
CssColor::red->toHexRgbString(true);
// Returns '#FF0000' (using the $short parameter):
CssColor::red->toHexRgbString(short : false);
// Returns '#FF0000FF' (using $alpha and $short parameters):
CssColor::red->toHexRgbString(true, false);
// Returns '#ff0000ff' (using $alpha, $short and $uppercase parameters):
CssColor::red->toHexRgbString(true, false, false);
// Returns 'ff0000ff' (using $alpha, $short, $uppercase and $sharp parameters):
CssColor::red->toHexRgbString(true, false, false, false);
// Returns 'rgb(100% 0% 0%)':
CssColor::red->toRgbString();
// Returns 'rgb(100% 0% 0% / 100%)' (using the $alpha parameter):
CssColor::red->toRgbString(alpha : true);
// Returns 'rgb(255,0,0)' (using the $legacy parameter):
CssColor::red->toRgbString(true);
// Returns 'rgba(255,0,0,1)' (using the $legacy and $alpha parameters):
CssColor::red->toRgbString(true, true);
```
You can also get a new `Color` **object** from any `CssColor` by using the `toCss()`, `toHexRgb()` or `toRgb()` method:
```php
toCss();
// Returns a new colors\HexRgb instance:
CssColor::red->toHexRgb();
// Returns a new colors\Rgb instance:
CssColor::red->toRgb();
```
[↑ Back to Top](#-color-a-modern-php-83-color-library)
## 🌈 Color Spaces
**Color** currently supports the following **color spaces** and formats:
### CSS
In **Color**, the `Css` color space refers to the **named colors** according to the [CSS specification](https://drafts.csswg.org/css-color-4/#named-colors). Because they are a predefined and standardized list of exact colors, they all can be accessed easily with [the CssColor Enum](#the-csscolor-enum).
> **Note** :
> `Css` colors **cannot** have an opacity value. If you want to apply transparency to a `Css` color, you first **have to** convert it into another color space. In the same way, if you convert a color with transparency into its `Css` equivalent, it will **lose** the transparency.
- **ColorSpace enum case** : `ColorSpace::Css` ;
- **Color class** : `Atomicptr\Color\Colors\Css` ;
- **Dedicated functions namespace** : `Atomicptr\Color\Utils\CSS` ;
- **Accepted aliases** : `css`, `html`, `web` ;
### Hexadecimal RGB
- **ColorSpace** case: `ColorSpace::HexRgb` ;
- **Color class** : `Atomicptr\Color\Colors\HexRgb` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\HexRGB` ;
- **Accepted aliases** : `hex`, `hexrgb`, `hex-rgb`, `hex_rgb`, `hexadecimal` ;
- **Coordinates** : `red`, `green`, `blue` ;
### HSL
- **ColorSpace** case: `ColorSpace::Hsl` ;
- **Color class** : `Atomicptr\Color\Colors\Hsl` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\HSL` ;
- **Accepted aliases** : `hsl`, `hsla` ;
- **Coordinates** : `hue`, `saturation`, `lightness` ;
### HSV
- **ColorSpace** case: `ColorSpace::Hsv` ;
- **Color class** : `Atomicptr\Color\Colors\Hsv` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\HSV` ;
- **Accepted aliases** : `hsv`, `hsb` ;
- **Coordinates** : `hue`, `saturation`, `value` ;
### HWB
- **ColorSpace** case: `ColorSpace::Hwb` ;
- **Color class** : `Atomicptr\Color\Colors\Hwb` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\HWB` ;
- **Accepted aliases** : `hwb` ;
- **Coordinates** : `hue`, `whiteness`, `blackness` ;
### Lab
- **ColorSpace** case: `ColorSpace::Lab` ;
- **Color class** : `Atomicptr\Color\Colors\Lab` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\Lab` ;
- **Accepted aliases** : `lab`, `cielab`, `cie-lab`, `cie_lab` ;
- **Coordinates** : `lightness`, `b`, `a` ;
### Lch
- **ColorSpace** case: `ColorSpace::Lch` ;
- **Color class** : `Atomicptr\Color\Colors\Lch` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\Lch` ;
- **Accepted aliases** : `lch`, `cielch`, `cie-lch`, `cie_lch` ;
- **Coordinates** : `lightness`, `chroma`, `hue` ;
### Linear RGB
- **ColorSpace** case: `ColorSpace::LinRgb` ;
- **Color class** : `Atomicptr\Color\Colors\LinRgb` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\LinRGB` ;
- **Accepted aliases** : `srgb-linear`, `linrgb`, `linsrgb`, `lin-rgb`, `lin_rgb`, `lin-srgb`, `lin_srgb` ;
- **Coordinates** : `red`, `green`, `blue` ;
### Linear P3
- **ColorSpace** case: `ColorSpace::LinP3` ;
- **Color class** : `Atomicptr\Color\Colors\LinP3` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\LinP3` ;
- **Accepted aliases** : `p3-linear`, `p3_linear`, `linp3`, `lin-p3`, `lin_p3` ;
- **Coordinates** : `red`, `green`, `blue` ;
### Linear ProPhoto
- **ColorSpace** case: `ColorSpace::LinProPhoto` ;
- **Color class** : `Atomicptr\Color\Colors\LinProPhoto` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\LinProPhoto` ;
- **Accepted aliases** : `prophoto-linear`, `prophoto_linear`, `linprophoto`, `lin-prophoto`, `lin_prophoto` ;
- **Coordinates** : `red`, `green`, `blue` ;
### OkLab
- **ColorSpace** case: `ColorSpace::OkLab` ;
- **Color class** : `Atomicptr\Color\Colors\OkLab` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\OkLab` ;
- **Accepted aliases** : `oklab`, `ok-lab`, `ok_lab` ;
- **Coordinates** : `lightness`, `a`, `b` ;
### OkLch
- **ColorSpace** case: `ColorSpace::OkLch` ;
- **Color class** : `Atomicptr\Color\Colors\OkLch` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\OkLch` ;
- **Accepted aliases** : `oklch`, `ok-lch`, `ok_lch` ;
- **Coordinates** : `lightness`, `chroma`, `hue` ;
### P3
- **ColorSpace** case: `ColorSpace::LinP3` ;
- **Color class** : `Atomicptr\Color\Colors\LinP3` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\LinP3` ;
- **Accepted aliases** : `display-p3`, `display_p3`, `p3` ;
- **Coordinates** : `red`, `green`, `blue` ;
### ProPhoto
- **ColorSpace** case: `ColorSpace::ProPhoto` ;
- **Color class** : `Atomicptr\Color\Colors\ProPhoto` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\ProPhoto` ;
- **Accepted aliases** : `prophoto`, `prophoto-rgb`, `prophoto_rgb` ;
- **Coordinates** : `red`, `green`, `blue` ;
### RGB
- **ColorSpace** case: `ColorSpace::Rgb` ;
- **Color class** : `Atomicptr\Color\Colors\Rgb` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\RGB` ;
- **Accepted aliases** : `rgb`, `rgba`, `srgb`, `s-rgb`, `s_rgb` ;
- **Coordinates** : `red`, `green`, `blue` ;
### XYZ-D50
- **ColorSpace** case: `ColorSpace::XyzD50` ;
- **Color class** : `Atomicptr\Color\Colors\XyzD50` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\XyzD50` ;
- **Accepted aliases** : `xyz-d50`, `xyz_d50`, `xyzd50` ;
- **Coordinates** : `x`, `y`, `z` ;
### XYZ-D65
- **ColorSpace** case: `ColorSpace::XyzD65` ;
- **Color class** : `Atomicptr\Color\Colors\XyzD65` ;
- **Dedicated functions** namespace : `Atomicptr\Color\Utils\XyzD65` ;
- **Accepted aliases** : `xyz-d65`, `xyz_d65`, `xyzd65`, `xyz` ;
- **Coordinates** : `x`, `y`, `z` ;
[↑ Back to Top](#-color-a-modern-php-83-color-library)
## 📜 License
**Color** is publicly shared under the **MIT License**. You can freely use it in any project. For more information, please read the included [License File](https://github.com/atomicptr/color/blob/main/LICENSE).
[↑ Back to Top](#-color-a-modern-php-83-color-library)
## ❤️ Thanks
A huge thanks to [Lea Verou](https://github.com/LeaVerou) and [Chris Lilley](https://github.com/svgeesus) for their incredible work and their precise articles on the subject. With a special thanks to Chris for the time and the answers he gave me during the implementation of this library.
Also since this is a fork, a huge thanks to [Matthieu Masta Denis](https://github.com/matthieumastadenis) for developing the original project.
[↑ Back to Top](#-color-a-modern-php-83-color-library)