Coder Social home page Coder Social logo

color's Introduction

A little library to handle color conversions and comparisons

Latest Version on Packagist Software License Build Status Quality Score Total Downloads Tests

A little library to handle color conversions and comparisons. Currently supports rgb, rgba, hex, hsl, hsla, CIELab, and xyz color formats as well as CIE76, CIE94, and CIEDE2000 color comparison algorithms.

$rgb = Rgb::fromString('rgb(55,155,255)');

echo $rgb->red(); // 55
echo $rgb->green(); // 155
echo $rgb->blue(); // 255

echo $rgb; // rgb(55,155,255)

$rgba = $rgb->toRgba(); // `Spatie\Color\Rgba`
$rgba->alpha(); // 1
echo $rgba; // rgba(55,155,255,1)

$hex = $rgb->toHex(); // `Spatie\Color\Hex`
$rgba->alpha(); // ff
echo $hex; // #379bff

$cmyk = $rgb->toCmyk(); // `Spatie\Color\Cmyk`
echo $cmyk; // cmyk(78,39,0,0)

$hsl = $rgb->toHsl(); // `Spatie\Color\Hsl`
echo $hsl; // hsl(210,100%,100%)

$hsb = $rgb->toHsb(); // `Spatie\Color\Hsb`
echo $hsb; // hsl(210,78.4%,100%)

$lab = $rgb->toCIELab();
echo $lab; // CIELab(62.91,5.34,-57.73)

$xyz = $rgb->toXyz();
echo $xyz; // xyz(31.3469,31.4749,99.0308)

$hex2 = Hex::fromString('#2d78c8');

$ratio = Contrast::ratio(Hex::fromString('#f0fff0'), Hex::fromString('#191970')); 
echo $ratio; // 15.0

$cie76_distance = Distance::CIE76($rgb, $hex2);
$cie76_distance = Distance::CIE76('rgba(55,155,255,1)', '#2d78c8'); // Outputs the same thing, Factory is built-in to all comparison functions
echo $cie76_distance; // 55.89468042667388

$cie94_distance = Distance::CIE94($rgb, $hex2);
echo $cie94_distance; // 13.49091942790753

$cie94_textiles_distance = Distance::CIE94($rgb, $hex2, 1); // Third parameter optionally sets the application type (0 = Graphic Arts [Default], 1 = Textiles)
echo $cie94_textiles_distance; // 7.0926538068477

$ciede2000_distance = Distance::CIEDE2000($rgb, $hex2);
echo $ciede2000_distance; // 12.711957696300898

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Installation

You can install the package via composer:

composer require spatie/color

Usage

The Color package contains a separate class per color format, which each implement a Color interface.

There are seven classes which implement the Color interface:

  • CIELab
  • Cmyk
  • Hex
  • Hsb
  • Hsl
  • Hsla
  • Rgb
  • Rgba
  • Xyz

interface Spatie\Color\Color

fromString(): Color

Parses a color string and returns a Color implementation, depending on the format of the input string.

Hex::fromString('#000000');
Rgba::fromString('rgba(255, 255, 255, 1)');
Hsla::fromString('hsla(360, 100%, 100%, 1)');

Throws an InvalidColorValue exception if the string can't be parsed.

Rgb, Rgba, Hsl and Hsla strings are allowed to have spaces. rgb(0,0,0) is just as valid as rgb(0, 0, 0).

red(): int|string

Return the value of the red color channel.

Hex::fromString('#ff0000')->red(); // 'ff'
Rgb::fromString('rgb(255, 0, 0)')->red(); // 255

green(): int|string

Return the value of the green color channel.

Hex::fromString('#00ff00')->green(); // 'ff'
Rgb::fromString('rgb(0, 255, 0)')->green(); // 255

blue(): int|string

Return the value of the blue color channel.

Hex::fromString('#0000ff')->blue(); // 'ff'
Rgb::fromString('rgb(0, 0, 255)')->blue(); // 255

toCmyk(): Cmyk

Convert a color to a Cmyk color.

Rgb::fromString('rgb(0, 0, 255)')->toCmyk();
// `Cmyk` instance; 'cmyk(100,100,0,0)'

toHex(): Hex

Convert a color to a Hex color.

Rgb::fromString('rgb(0, 0, 255)')->toHex();
// `Hex` instance; '#0000ff'

When coming from a color format that doesn't support opacity, it can be added by passing it to the $alpha parameter.

toHsb(): Hsb

Convert a color to a Hsb color.

Rgb::fromString('rgb(0, 0, 255)')->toHsb();
// `Hsl` instance; 'hsb(240, 100%, 100%)'

toHsl(): Hsl

Convert a color to a Hsl color.

Rgb::fromString('rgb(0, 0, 255)')->toHsl();
// `Hsl` instance; 'hsl(240, 100%, 50%)'

When coming from a color format that supports opacity, the opacity will simply be omitted.

Rgba::fromString('rgba(0, 0, 255, .5)')->toHsl();
// `Hsl` instance; 'hsl(240, 100%, 50%)'

toHsla(float $alpha = 1): Hsla

Convert a color to a Hsla color.

Rgb::fromString('rgb(0, 0, 255)')->toHsla();
// `Hsla` instance; 'hsla(240, 100%, 50%, 1.0)'

When coming from a color format that doesn't support opacity, it can be added by passing it to the $alpha parameter.

Rgb::fromString('rgb(0, 0, 255)')->toHsla(.5);
// `Hsla` instance; 'hsla(240, 100%, 50%, 0.5)'

toRgb(): Rgb

Convert a color to an Rgb color.

Hex::fromString('#0000ff')->toRgb();
// `Rgb` instance; 'rgb(0, 0, 255)'

When coming from a color format that supports opacity, the opacity will simply be omitted.

Rgba::fromString('rgb(0, 0, 255, .5)')->toRgb();
// `Rgb` instance; 'rgb(0, 0, 255)'

toRgba(float $alpha = 1): Rgba

Convert a color to a Rgba color.

Rgb::fromString('rgb(0, 0, 255)')->toRgba();
// `Rgba` instance; 'rgba(0, 0, 255, 1)'

When coming from a color format that doesn't support opacity, it can be added by passing it to the $alpha parameter.

Rgba::fromString('rgb(0, 0, 255)')->toRgba(.5);
// `Rgba` instance; 'rgba(0, 0, 255, .5)'

__toString(): string

Cast the color to a string.

(string) Rgb::fromString('rgb(0, 0, 255)'); // 'rgb(0,0,255)'
(string) Rgba::fromString('rgb(0, 0, 255, .5)'); // 'rgb(0,0,255,0.5)'
(string) Hex::fromString('#0000ff'); // '#0000ff'
(string) Hsl::fromString('hsl(240, 100%, 50%)'); // 'hsl(240, 100%, 50%)'
(string) Hsla::fromString('hsla(240, 100%, 50%, 1.0)'); // 'hsla(240, 100%, 50%, 1.0)'

Factory::fromString(): Color

With the Factory class, you can create a color instance from any string (it does an educated guess under the hood). If the string isn't a valid color string in any format, it throws an InvalidColorValue exception.

Factory::fromString('rgb(0, 0, 255)'); // `Rgb` instance
Factory::fromString('#0000ff'); // `Hex` instance
Factory::fromString('hsl(240, 100%, 50%)'); // `Hsl` instance
Factory::fromString('Hello world!'); // `InvalidColorValue` exception

Changelog

Please see CHANGELOG for more information what has changed recently.

Testing

$ composer test

Contributing

Please see CONTRIBUTING for details.

Security

If you've found a bug regarding security please mail [email protected] instead of using the issue tracker.

Credits

About Spatie

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

License

The MIT License (MIT). Please see License File for more information.

color's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

color's Issues

Add typehints

Can't do it now since it would be a breaking change.

  • Color
    • red, green, blue: int
    • fromString: self

Define a common 'opacity' value for each color instance

While this might be fixed by transitioning to use of a common / universal color definition for internal storage (i.e. all colours are instances of a generalised colour definition, converted on demand to whatever format is requested), until then I think there is a case for defining an additional property for colour classes which evaluates to 0->1 opacity.

Consider this example - imagine you do the following:

$the_colour = @Factory::fromString('#22334455');
echo $the_colour->alpha(); // 55;

If you then want to convert this to RGBA you might do

echo $the_colour->rbga($the_color->alpha()); // error - due to alpha (55) value being out of required range (0->1)

So to make this conversion the developer using library needs to first check what format the colour being converted is and adjust the alpha value to one that will be accepted by the RGBA method. This is unnecessary, and by making it happen outside of the library increases liklihood of errors being introduced.

A better solution might be to calculate an "opacity" value for each colour definition - translating whatever opacity format information is held in the colour format into a value in range 0->1 - so in this case the hex 55 value would translate into 0.33 opacity value.

Then developers could use the following form without worry:

echo $the_colour->rbga($the_color->opacity()); // rgba(34,51,68,0.33)

Does this sound like it is worth doing? Or is work on a unified colour model a better thing to spend time on?

HSL: hue = 0 ... Return value of Spatie\Color\Convert::hslValueToRgb() must be of the type array, none returned

Hi,
I get an error, when hue value is 0:

Return value of Spatie\Color\Convert::hslValueToRgb() must be of the type array, none returned in
...\vendor\spatie\color\src\Convert.php:53

Testing:

$red = '#fc0000';
$redHsl = Hex::fromString($red)->toHsl(); // hue protected => 0.0, saturation protected => 100.0, lightness protected => 49.411764705882355
$redRgb = $redHsl->toRgb();

or

$red = '#fc0000';
$redHsl = Hex::fromString($red)->toHsl(); // hue protected => 0.0, saturation protected => 100.0, lightness protected => 49.411764705882355
$redHslString = $redHsl->__toString();
$redRgb = Hsl::fromString($redHslString)->toRgb();

produces:
TypeError - Return value of Spatie\Color\Convert::hslValueToRgb() must be of the type array, none returned
in ...\vendor\spatie\color\src\Convert.php:53

Seems like the function hslValueToRgb() does not handle the value: $h == 0; properly?

Replacing from:

$h = (360 + ($hue % 360)) % 360;  // hue values can be less than 0 and greater than 360. This normalises them into the range 0-360.

to:

$h = (360 + ($hue % 360)) % 360;  // hue values can be less than 0 and greater than 360. This normalises them into the range 0-360.
		if ($h == 0) {
			$h = 360;
		}

solves the problem programmatically, but I have no idea, if it solves it correctly when it comes to creating colors. ???

Jan

Constructive bound checking on RGB/RGBA values

I have developed a modification for RGB and RGBA that accepts parameter values for R G B as %, as per spec for these color definitions - so for example making this possible:

$rgb = Rgb::fromString('rgb(30%, 50%, 70%)');
echo $rgb; // rgb(77,128,179)

In doing this I have (through force of habit) added boundary checks that coerce the values created from strings to sit within the range 0-255 (or 0-1 for opacity) - using simple min/max testing.

I went to write some tests for these adapted fromString conversions I noticed that the current tests are set to throw an exception if RGB values exceed boundaries. I understand why this might be done, but in general I think it is an unforgiving way of operating - it is kinder / more constructive to the developer to return a boundary value when offered value exceeds the boundary than to kill the php process - so if an alpha value of 1.5 is specified interpret this as 1.

I would value some policy guidance on whether this kind of constructive boundary checking is allowed or not before I submit the PR with the adapted code: hopefully this will save time compared to submitting the PR and then having to resubmit when constructive boundary checking is deemed inappropriate.

Look forward to hearing thoughts etc.

Wrong version in `composer.json` (1.3.0 instead of 1.4.0)

Hi,

I think that the version is wrong in the composer.json file and should be v1.4.0:

{
    "name": "spatie/color",
    "description": "A little library to handle color conversions",
-   "version": "v1.3.0",
+   "version": "v1.4.0",
    "keywords": [
        "spatie",
        "color",
        "conversion",
        "rgb"
    ],
    "homepage": "https://github.com/spatie/color",
    "license": "MIT",
    "authors": [
        {
            "name": "Sebastian De Deyne",
            "email": "[email protected]",
            "homepage": "https://spatie.be",
            "role": "Developer"
        }
    ],
    "require": {
        "php" : "^7.3|^8.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^6.5||^9.0"
    },
    "autoload": {
        "psr-4": {
            "Spatie\\Color\\": "src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Spatie\\Color\\Test\\": "tests"
        }
    },
    "scripts": {
        "test": "vendor/bin/phpunit"
    },
    "config": {
        "sort-packages": true
  }
}

Regards

HSLA -> RGBA looses transparency value

I did this:

$colour = "hsla(331,96%,90%,0.76)"
$the_colour = @Factory::fromString($colour);

This creates a Spatie\Color\Hsla object with this value:

$the_colour: Spatie\Color\Hsla
 hue: 331
 saturation: 96
 lightness: 90
 alpha: 0.76

If I now convert this to RGBA thusly:

$the_rgba_colour = $the_colour->toRgba();

I get a Spatie\Color\Rgba object with this value:

$the_rgba_colour: Spatie\Color\Rgba
 red: 254
 blue: 205
 green: 229
 alpha: 1

The correct value of alpha in this case should be 0.76.

Does anyone know why I get this result? I don't think I'm doing anything wrong vis the library, but would value thoughts.

Use of Factory::fromString() rather than a specific colour format object is simply due to use case being considered one where it is uncertain what colour format string might be supplied.

Thanks in advance for anyone who can offer any insight etc.

Convert color names

I'm looking for a library that converts all my colors into the same format and stumbled up on your library. IT looks like a neat start. However, I also need to be able to convert a string like red to something like #FF0000. Any reason not to support that?

Support 3 digit hex values

While usually a minor inconvenience to convert, generally hex values can be written as 3 digit codes when all three values (red, green and blue) have the same double digits, e.g. #ff00aa can be rewritten as shorthand #f0a. While not commonly used, it would be nice to have support for this to avoid having to handle this edge case manually.

Converting Hex to Hsl for #000 & #fff gets division by zero

Hi there

First of all thank you very much for this package as it is very useful, unfortunately when I try to convert the pure black or white colours it fails with division by zero error:

Hex::fromString('#000000')->toHsl()
Hex::fromString('#ffffff')->toHsl()

I think the following fix will sort this issue out:

In src/Convert.php line 77:

Replace this line:

            $saturation = $delta / (1 - abs((2 * $lightness) - 1));

with the following:

        if( $lightness > 0 && $lightness < 1) {
            $saturation = $delta / (1 - abs((2 * $lightness) - 1));
        }else {
            $saturation = 0;
        }

BUG : Hex color to HSL

Hi everyone,

For example, if I convert #a8a8a8 hex color to Hsl, I do :

Hex::fromString("#a8a8a8")->toHsl()

I've got an error on Spatie\Color::class when delta is zero.

red, blue and green have same value (0.65882352941176) so $cmin and $cmax have same value

I think is the strict type on

if ($delta !== 0) {

Idea: Add opacity support to Hex colors

Hex colors can contain opacity data by adding them to the beginning of the color code.

For example: #66000000 is black with 40% alpha transparency.

Some info here: https://gist.github.com/lopspower/03fb1cc0ac9f32ef38f4

Just an idea, I may try tackling this at some point but I also don't want it to be a breaking change so maybe the best way of going about it would be to add a fourth optional parameter to the Hex constructor.

Consolidate color spaces to a single class

Brain dump incoming

Consolidate all color spaces in a single color class that holds the color information.

rgb, rgba and hex all use the same color space. hls uses a different one so would need to be stored differently or we'd lose data.

API sketch:

Color::fromString('rgb(255, 0, 255)');

// Formats return diffrent objects depending on the  format
$color->rgb()->__toString();
$color->rgb()->red();
$color->hex()->red();

// $color->rgb()->toHls() should also be possible

// Changing color spaces requires an explicit conversion (different implementation of `Color`)
// For example, you can't get `red` from a `hls` color
$color->toHls()->hue();

Incorrect conversion from HEX to HSL* with this color.

Hi, I just found this issue trying to convert #DC3545 to an hsl value, the hue returned is -5.748502994012 instead of 354.

You can try this method inside FactoryTest::class:

    public function test_it_should_return_correct_hsa_value_from_hex() {

        $sut = Factory::fromString('#dc3545' );

	$this->assertStringMatchesFormat( '#dc3545', (string) $sut->toHex(), '' );
	$this->assertStringMatchesFormat( 'rgb(220,53,69)', (string) $sut->toRgb(), '' );
        $this->assertStringMatchesFormat( 'hsl(354,70%,54%)', (string) $sut->toHsl(), '' );
        $this->assertStringMatchesFormat( 'hsla(354,70%,54%,1)', (string) $sut->toHsla(), '' );
    }

This is part of the tests output:

There was 1 failure:

1) Spatie\Color\Test\FactoryTest::test_it_should_return_correct_hsa_value_from_hex
Failed asserting that string matches format description.
--- Expected
+++ Actual
@@ @@
-hsl(354,70%,54%)
+hsl(-6,70%,54%)

Maybe the issue is here

$hue = 60 * fmod(($g - $b) / $delta, 6);

The hex to rgb conversion is fine, the rgb value returned is 220, 53, 69, so it should be only the rgb to hsl in the line above.

Support opacity in all color types

Enhancement request & proposal:

The color interface gets an opacity value that can be null. This value is retained through any color type conversions. If not part of an initial color it is simply null. I'm not tied to this implementation, but my point is that I don't think it would be that complicated (feel free to correct me though....). This would also mirror the way that the css specification now allows an optional opacity parameter for both hsl() and rgb() functions, rather than considering them to be different color types. This proposal would also mean that the opacity information is never lost if it was ever there (if someone wanted to explicitly make it 0, they could do so via an adjustment function of some sort).

Error in CIELab regexp

Example
$rgb = new \Spatie\Color\Rgb(0, 0, 0); \Spatie\Color\CIELab::fromString((string) $rgb->toCIELab());

Input values are not always floats and the validator will throw exception

CIELab color string CIELab(0,0,0) is malformed. A CIELab color contains 3 comma separated values, wrapped in CIELab(), e.g. CIELab(62.91,5.34,-57.73)

RGB and RGBA should accept % values

Currently neither the RGB nor RGBA classes accept values defined as percentages.
As noted here, both should accept either integer values in range 0-255, or a % in range 0-100, where 100% is then converted to 255.

Convert to CMYK

Hi. This code
$rgb = Rgb::fromString('rgb(2,30,33)');
echo $rgb->toCmyk();
throw the error "Cmyk value yellow must be a number between 0 and 1". Why?
the right answer is cmyk(94%,9%,0%,87%)

Could not find package spatie/color in a version matching "1.4.0"

Hi

I noticed that it is impossible to install version 1.4.0, while it is quite possible to install version 1.3.0.

With this command:

composer require spatie/color:1.4.0

I get this error:

Could not find package spatie/color in a version matching "1.4.0" and a stability matching "dev". 

I guess it's because the release of the version 1.4.0 is not available in packagist, right? Or my issue comes from somewhere else?

Thanks!

Regards

Bug Division by Zero Rgb to Cmyk

I am using version 1.5.2 (latest) on PHP 8.1 and getting an error by executing

$cmyk = (new Spatie\Color\Rgb(0,0,0))->toCmyk(); or
$cmyk = (new Spatie\Color\Hex('00', '00', '00'))->toCmyk();

Error is:

PHP Error: Division by zero in /.../vendor/spatie/color/src/Convert.php on line 67

The error is related to https://github.com/spatie/color/blob/main/src/Convert.php#L57

When red, green and blue are 0, then $keyNeg is also 0

I can only do a PR maybe in 2 weeks or so.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.