ChatGPT解决这个技术问题 Extra ChatGPT

How to generate lighter/darker color with PHP?

I have a hex value of some color, for example #202010.

How to generate a new color which is either lighter or darker given in percent (ie. 20% darker) in PHP?

You already asked this question, better to try to implement the Javascript solution you were given and comment more on that question than start a new one.
possible duplicate of Generate gradient color from PHP.
If you're doing this for a webapp/site I'm of the opinion that using LESS or SASS and CSS, or javascript methods, would be more efficient solutions. But my perspective may be skewed as I prefer PHP/node/C# etc... to be used to create a backend service for the front end tech to interact with, (as opposed to conflating them into one mushed up thing like old ASP.NET so painfully does/did).
Even in the other question, he asked for PHP/CSS - not Javascript.

T
Torkil Johnsen

Adjusting colour by percent, as in the example given by Frxstrem, is not ideal.

If your colour is black (0,0,0 in RGB), you will be multiplying by zero, which will not yield any change at all. If your colour is dark gray (for instance 2,2,2 in RGB), you will have to lighten by 50% to just move up to (3,3,3). On the other hand, if you have an RGB colour of (100,100,100), the adjustment of 50% will move you up to (150,150,150), which is a much bigger change in comparison.

A much better solution would be to adjust by step/number (0-255) instead of by percent, for instance like this (PHP code):

Edit 2014-01-06: Cleaned up the code a bit.

function adjustBrightness($hex, $steps) {
    // Steps should be between -255 and 255. Negative = darker, positive = lighter
    $steps = max(-255, min(255, $steps));

    // Normalize into a six character long hex string
    $hex = str_replace('#', '', $hex);
    if (strlen($hex) == 3) {
        $hex = str_repeat(substr($hex,0,1), 2).str_repeat(substr($hex,1,1), 2).str_repeat(substr($hex,2,1), 2);
    }

    // Split into three parts: R, G and B
    $color_parts = str_split($hex, 2);
    $return = '#';

    foreach ($color_parts as $color) {
        $color   = hexdec($color); // Convert to decimal
        $color   = max(0,min(255,$color + $steps)); // Adjust color
        $return .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT); // Make two char hex code
    }

    return $return;
}

Thanks! Came in handy today.
Awesome, I used this in my wordpress theme!
The steps cannot simply be added to each color value equally, as this will alter the shade of the color you are working with. To keep the same shade of a color, which is the desired result, it must be a fractional part of the R, G, and B values. This looks like: $r = max(0,min(255,$r + ($r * ($steps / 255))));
Your explanation of why multiplying by a percentage is wrong happens to be exactly how Photoshop changes its colors when you set the brightness (HSB) to variable and scrub up and down the slider from dark to light. Try it out. Set an RGB=(127,127,1) and the B stays in the bounds of 0-2 when you scrub from 0 brightness to 100 brightness.
Thanks! I just changed the beginning so you can use percent instead of -255 or 255. function adjustBrightness($hex, $percent, $darken = true) { $brightness = $darken ? -255 : 255; $steps = $percent*$brightness/100; …. Usage: adjustBrightness('#c2002f', 10, false ) This will lighten my color.
m
maliayas

Torkil Johnsen's answer is based on fixed step which doesn't manipulate only brightness but also slightly changes the hue. Frxstrem's method has flaws too as Torkil Johnsen noted.

I've taken this approach from a Github comment and improved the code. It works perfectly for any case.

/**
 * Increases or decreases the brightness of a color by a percentage of the current brightness.
 *
 * @param   string  $hexCode        Supported formats: `#FFF`, `#FFFFFF`, `FFF`, `FFFFFF`
 * @param   float   $adjustPercent  A number between -1 and 1. E.g. 0.3 = 30% lighter; -0.4 = 40% darker.
 *
 * @return  string
 *
 * @author  maliayas
 */
function adjustBrightness($hexCode, $adjustPercent) {
    $hexCode = ltrim($hexCode, '#');

    if (strlen($hexCode) == 3) {
        $hexCode = $hexCode[0] . $hexCode[0] . $hexCode[1] . $hexCode[1] . $hexCode[2] . $hexCode[2];
    }

    $hexCode = array_map('hexdec', str_split($hexCode, 2));

    foreach ($hexCode as & $color) {
        $adjustableLimit = $adjustPercent < 0 ? $color : 255 - $color;
        $adjustAmount = ceil($adjustableLimit * $adjustPercent);

        $color = str_pad(dechex($color + $adjustAmount), 2, '0', STR_PAD_LEFT);
    }

    return '#' . implode($hexCode);
}

Here is an example result:

https://i.stack.imgur.com/7mjfp.png


Excellent! Works great with Kiran's TooLightYIQ(hexcolor) function, here: link
This might not be the color perfect way to do it, but for my use case it is enough, AND it is simpler, just a short function :)
Please note that the dechex-function requires an integer and the example above will provide a float. This will break in newer PHP-versions.
C
Community

The answers are wrong.

Using RGB model is a conceptual error.

You need to transform the color from RGB (or Hex form) into HSL.

That is Hue, Saturation, Lightness.

Once you convert it from RGB into HSL, to lighten up the color you simply adjust the L value (lightness) by 10%. Then once you are done you convert back from HSL to RGB and you are done.

Voila!

RGB to HSV in PHP


C
Cay

Here's an example:

<?php
$color = '#aabbcc'; // The color we'll use

Extract the colors. I'd prefer to use regular expressions, though there are probably other more efficient ways too.

if(!preg_match('/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i', $color, $parts))
  die("Not a value color");

Now we have red in $parts[1], green in $parts[2] and blue in $parts[3]. Now, let's convert them from hexadecimal to integers:

$out = ""; // Prepare to fill with the results
for($i = 1; $i <= 3; $i++) {
  $parts[$i] = hexdec($parts[$i]);

Then we'll decrease them by 20 %:

  $parts[$i] = round($parts[$i] * 80/100); // 80/100 = 80%, i.e. 20% darker
  // Increase or decrease it to fit your needs

Now, we'll turn them back into hexadecimal and add them to our output string

  $out .= str_pad(dechex($parts[$i]), 2, '0', STR_PAD_LEFT);
}

Then just add a "#" to the beginning of the string, and that's it!


for this I just added the '#' into the $out = ""; part so it now reads $out = "#"; // Prepare to fill with the results
p
pgee70

I was interested in this, but my question was how do I add a opacity to a colour?

I wanted a colour to fade, not made lighter. i found this: http://www.gidnetwork.com/b-135.html and it worked great- code posted from original site for SO readers.

function color_blend_by_opacity( $foreground, $opacity, $background=null )
{
    static $colors_rgb=array(); // stores colour values already passed through the hexdec() functions below.
    $foreground = str_replace('#','',$foreground);
    if( is_null($background) )
        $background = 'FFFFFF'; // default background.

    $pattern = '~^[a-f0-9]{6,6}$~i'; // accept only valid hexadecimal colour values.
    if( !@preg_match($pattern, $foreground)  or  !@preg_match($pattern, $background) )
    {
        trigger_error( "Invalid hexadecimal colour value(s) found", E_USER_WARNING );
        return false;
    }

    $opacity = intval( $opacity ); // validate opacity data/number.
    if( $opacity>100  || $opacity<0 )
    {
        trigger_error( "Opacity percentage error, valid numbers are between 0 - 100", E_USER_WARNING );
        return false;
    }

    if( $opacity==100 )    // $transparency == 0
        return strtoupper( $foreground );
    if( $opacity==0 )    // $transparency == 100
        return strtoupper( $background );
    // calculate $transparency value.
    $transparency = 100-$opacity;

    if( !isset($colors_rgb[$foreground]) )
    { // do this only ONCE per script, for each unique colour.
        $f = array(  'r'=>hexdec($foreground[0].$foreground[1]),
                     'g'=>hexdec($foreground[2].$foreground[3]),
                     'b'=>hexdec($foreground[4].$foreground[5])    );
        $colors_rgb[$foreground] = $f;
    }
    else
    { // if this function is used 100 times in a script, this block is run 99 times.  Efficient.
        $f = $colors_rgb[$foreground];
    }

    if( !isset($colors_rgb[$background]) )
    { // do this only ONCE per script, for each unique colour.
        $b = array(  'r'=>hexdec($background[0].$background[1]),
                     'g'=>hexdec($background[2].$background[3]),
                     'b'=>hexdec($background[4].$background[5])    );
        $colors_rgb[$background] = $b;
    }
    else
    { // if this FUNCTION is used 100 times in a SCRIPT, this block will run 99 times.  Efficient.
        $b = $colors_rgb[$background];
    }

    $add = array(    'r'=>( $b['r']-$f['r'] ) / 100,
                     'g'=>( $b['g']-$f['g'] ) / 100,
                     'b'=>( $b['b']-$f['b'] ) / 100    );

    $f['r'] += intval( $add['r'] * $transparency );
    $f['g'] += intval( $add['g'] * $transparency );
    $f['b'] += intval( $add['b'] * $transparency );

    return sprintf( '%02X%02X%02X', $f['r'], $f['g'], $f['b'] );
}

p
phoenix

If you want a simple implementation and you don't care that much about the values being specifically above 50% lightness (or whatever your threshold), you can use my solution for lighter colors:

$color = sprintf('#%06X', mt_rand(0xFFFFFF / 1.5, 0xFFFFFF));

The idea is to generate a random color in the higher part of the palette. You can adjust the results to be more or less dark by changing the "1.5" value:

larger will expand the palette into darker colors

smaller will curb it to lighter colors

You can do the same for darker colors by setting the starting point of the random function to "0x000000" and dividing the end limit:

$color = sprintf('#%06X', mt_rand(0x000000, 0xFFFFFF / 1.5));

I know this is not a precise but it works for me.


S
Slawa

https://github.com/mikeemoo/ColorJizz-PHP allows to convert to HSL, change lightness component and convert back to RGB.


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now