如何使用PHP生成更浅或更深的颜色?

66

我有一个颜色的十六进制值,例如#202010

如何在PHP中生成一个新的颜色,使其比现有颜色更亮或更暗,给定一个百分比(例如,比现有颜色暗20%)


3
你已经问过这个问题了,最好尝试实现你得到的JavaScript解决方案,并在那个问题上添加更多的评论,而不是提出一个新问题。 - Kyle
如果你是在为一个网站或者Web应用程序做这件事情,我认为使用LESS或SASS和CSS,或者JavaScript方法,会是更高效的解决方案。但是我的观点可能有所偏颇,因为我更喜欢使用PHP/node/C#等来创建后端服务,供前端技术进行交互(而不是像旧版ASP.NET那样将它们混合成一个东西)。 - MER
即使在另一个问题中,他要求的是PHP/CSS,而不是Javascript。 - SQLiteNoob
7个回答

142

按照Frxstrem所给的例子,通过百分比来调整颜色并不理想。

如果您的颜色是黑色(RGB中的0,0,0),那么您将乘以零,这根本没有任何变化。如果您的颜色是深灰色(例如RGB中的2,2,2),则必须使亮度增加50%才能达到(3,3,3)。另一方面,如果您的RGB颜色为(100,100,100),那么50%的调整将使您上升到(150,150,150),相比之下是一个更大的变化。

一个更好的解决方案是通过步长/数字(0-255)而不是百分比来进行调整,例如像这样(PHP代码):

编辑2014-01-06:稍微清理了代码。

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;
}

1
谢谢!今天派上用场了。 - 472084
1
太棒了,我在我的WordPress主题中使用了它! - Dafen
8
不能简单地将步骤均等地添加到每个颜色值中,因为这样会改变你正在处理的颜色的色调。为了保持相同的颜色色调,也就是想要的结果,必须是 R、G 和 B 值的分数部分。具体做法如下: $r = max(0,min(255,$r + ($r * ($steps / 255)))); - Wes Cossick
2
当你将亮度(HSB)设置为可变并上下滑动滑块从暗到亮时,你解释为什么乘以百分比是错误的恰好是Photoshop改变其颜色的方式。试一试。将RGB =(127,127,1)设置为初始值,当你从0亮度向100亮度滑动时,B保持在0-2的范围内。 - Jeff
2
谢谢!我刚刚更改了开头,这样你就可以使用百分比而不是-255或255。function adjustBrightness($hex, $percent, $darken = true) { $brightness = $darken ? -255 : 255; $steps = $percent*$brightness/100; …。用法:adjustBrightness('#c2002f', 10, false ) 这将使我的颜色变亮。 - xWaZzo
显示剩余2条评论

67

Torkil Johnsen的回答基于固定步长,这不仅会改变亮度还会略微改变色相。而Frxstrem的方法也有缺陷,正如Torkil Johnsen所指出的。

我采用了一个Github评论中的方法,并对代码进行了改进。它适用于任何情况,效果完美。

/**
 * 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);
}

这是一个示例结果:

示例


1
太棒了!与Kiran的TooLightYIQ(hexcolor)函数完美配合,链接在这里:link - user2607743
这可能不是完美的方法,但对于我的用例来说已经足够了,而且更简单,只需要一个短函数 :) - Larzan
1
请注意,dechex函数需要一个整数作为参数,而上面的示例提供了一个浮点数。 这将在较新版本的PHP中出现错误。 - jerome2710
1
这是一个很好的解决方案,比被接受的答案更好。请注意,对于某些人来说可能并不明显,但第二个参数(百分比参数)必须表示为小数。例如 $lighter_color_70_percent = adjustBrightness("#aa00ff",.7); 例如 $darker_color_30_percent = adjustBrightness("#aa00ff",-.3); - user2662680

29

答案错误。

使用RGB模型是一个概念上的错误。

你需要将颜色从RGB(或十六进制形式)转换为HSL。

即色相、饱和度和亮度。

一旦你将其从RGB转换为HSL,要使颜色变亮,只需将L值(亮度)调整10%。然后完成后,将HSL转换回RGB,就完成了。

大功告成!

PHP中的RGB到HSV


23

这是一个例子:

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

提取颜色。我更喜欢使用正则表达式,虽然可能有其他更有效的方法。

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

现在我们有红色在$parts [1]中,绿色在$parts [2]中,蓝色在$parts [3]中。现在让我们将它们从十六进制转换为整数:

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

然后我们将把它们降低 20%:

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

现在,我们将把它们转换回十六进制,并将它们添加到我们的输出字符串中。

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

然后只需在字符串开头添加"#",就可以了!


1
为此,我只需在$out = "";部分中添加“#”,因此现在将其更改为$out = "#"; //准备用结果填充 - Oliver Whysall

5

我对此很感兴趣,但我的问题是如何在颜色中添加不透明度

我想让颜色渐变,而不是变浅。我找到了这个链接: http://www.gidnetwork.com/b-135.html 它很有效- 我将原网站的代码贴在SO读者的帖子中。

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'] );
}

4

如果你想要一个简单的实现,而且对于颜色值并不特别在意是否超过50%的亮度(或者其他阈值),那么你可以使用我的解决方案来获取更轻的颜色:

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

这个想法是在调色板的高端生成一个随机颜色。通过改变“1.5”值,您可以调整结果为更暗或更浅:

  • 放大将扩展调色板到更深的颜色
  • 缩小将限制它到较浅的颜色

您还可以通过将随机函数的起始点设置为“0x000000”,并将结束限制除以相同的值来做出相同的更暗的颜色。

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

我知道这不是很精确,但对我来说很实用。


2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接