3

我正在构建一个颜色类,并且希望添加更多(颜色,百分比)和更少(颜色,百分比)的操作。这需要能够添加和减去颜色,而我在算术方面遇到了困难。如何使用 RGB 或 HSB(HSV) 或 HEX 执行以下操作:

手术 -echo color('blue')->more('yellow', 100%);

  • 蓝色 + 黄色 = 绿色

或者

手术 -echo color('blue')->more('yellow', 50%);

  • 蓝色 + .5 * 黄色 = 深绿色

对于减法,我对此有一个非常模糊的概念:

手术 -echo color('orange-yellow')->less('red', 50%);

  • 橙黄色 - .5 * 红色 = 黄色

编辑: 好的,感谢您到目前为止的输入。不幸的是,我尝试在 CYM 中将 CYM 相互添加为红色 (255, 0, 0) ~= (0, 1, 1) ,然后如果将其添加到蓝色 (0, 0, 255) ~= (1, 1 , 0) 它将等于 (1, 2, 1) 或 (1, 1, 1) 在 CYM 中是黑色的。

我使用色相饱和度亮度 (HSB) 得到了最接近的结果。事实上,它适用于除红色之外的所有颜色组合。我相信这是因为红色位于色调的开头和结尾(色调使用度数 [0, 360])。

您的任何想法将不胜感激!


编辑2:

好的,所以在玩了一晚上之后,这是一种我非常满意的“更多”方法。

它使用HSB(Hue-Saturation-Brightness)颜色模型,现在不要问我为什么我的CYM不起作用。我是一个色彩新手。看起来它确实可以工作,因为这就是打印机混合颜色的方式。我非常喜欢 HSB 模型,以及使用颜色选择器时 Photoshop 显示的内容。

我已经添加它作为答案,所以让我知道你们的想法!再次感谢!


任何帮助都会很棒!

谢谢,马特

4

7 回答 7

3

使用 RGB 颜色空间的一种解决方案是在内部表示颜色 - 红色、绿色、值。当需要十六进制表示时,从当前值中生成一个并将其发回。

more和方法然后less简单地操作当前的红色、绿色或蓝色值。

public function more($color, $percentage) {
    $this->color[$color] += $this->color[$color] * $percentage;
}

转换为十六进制字符串

public function toHex() {
    $red = $this->color['red'];
    $green = $this->color['green'];
    $blue = $this->color['blue'];
    return sprintf("%02X%02X%02X", $red, $green, $blue);
}

将字符串转换为'orange-green'它的 RGB 组件是一个稍微不同的问题。

于 2010-07-19T05:56:09.653 回答
2

那很有趣!

例子:

// examples
$c = Color(0x08090a)->more( 0xFF0000 , 100 )->remove(0x110000)->decrease(35)->add(0x002314);
$c->red = 0xF2;
$c->red->decrease(25);

您可以检查所有方法的来源,简短版本是添加、删除、增加、减少、更多、更少 - 元素和颜色的完整链接,添加了辅助函数 Color() 以使事情变得更容易。

<?php

class ColorElement {

    private $value;

    public function __construct( $value = 0 )
    {
        $this->setValue( $value );
    }

    public function add( $value )
    {
        $value = self::fixValue($value);
        $this->value = self::fixValue( $this->value + $value );
        return $this;
    }

    public function remove( $value )
    {
        $value = self::fixValue($value);
        $this->value = self::fixValue( $this->value - $value );
        return $this;
    }

    public function increase( $percentage=100 )
    {
        $percentage = self::fixPercentage($percentage);
        $this->value = self::fixValue( $this->value + (int)(($this->value/100)*$percentage) );
        return $this;
    }

    public function decrease( $percentage=100 )
    {
        $percentage = self::fixPercentage($percentage);
        $this->value = self::fixValue( $this->value - (int)(($this->value/100)*$percentage) );
        return $this;
    }

    public function less( $value , $percentage=100 )
    {
        $percentage = self::fixPercentage($percentage);
        $value = self::fixValue($value);
        $this->value = self::fixValue( $this->value - (int)(($value/100)*$percentage) );
        return $this;
    }

    public function more( $value , $percentage=100 )
    {
        $percentage = self::fixPercentage($percentage);
        $value = self::fixValue($value);
        $this->value = self::fixValue( $this->value + (int)(($value/100)*$percentage) );
        return $this;
    }

    public function setValue( $value )
    {
        $this->value = self::fixValue($value);
        return $this;
    }

    public function getValue()
    {
        return $this->value;
    }

    public function __toString()
    {
        return sprintf('%02X' , $this->value);
    }

    public static function fixValue( $value )
    {
        return $value < 0 ? 0 : ($value > 255 ? 255 : $value);
    }

    public static function fixPercentage( $percentage )
    {
        return $percentage < 0 ? 0 : ($percentage > 100 ? 100 : $percentage);
    }

}

class Color {

    private $_red;
    private $_green;
    private $_blue;

    public function __construct( $hex=0x000000 )
    {
        $this->_red = new ColorElement();
        $this->_green = new ColorElement();
        $this->_blue = new ColorElement();
        $this->setColor($hex);
    }

    public function add( $hex )
    {
        list($red, $green, $blue) = self::hexRGB($hex);
        $this->_red->add( $red );
        $this->_green->add( $green );
        $this->_blue->add( $blue );
        return $this;
    }

    public function remove( $hex )
    {
        list($red, $green, $blue) = self::hexRGB($hex);
        $this->_red->remove( $red );
        $this->_green->remove( $green );
        $this->_blue->remove( $blue );
        return $this;
    }

    public function increase( $percentage=100 )
    {
        $this->_red->increase( $percentage );
        $this->_green->increase( $percentage );
        $this->_blue->increase( $percentage );
        return $this;
    }

    public function decrease( $percentage=100 )
    {
        $this->_red->decrease( $percentage );
        $this->_green->decrease( $percentage );
        $this->_blue->decrease( $percentage );
        return $this;
    }

    public function less( $hex , $percentage=100 )
    {
        list($red, $green, $blue) = self::hexRGB($hex);
        $this->_red->less( $red , $percentage );
        $this->_green->less( $green , $percentage );
        $this->_blue->less( $blue , $percentage );
        return $this;
    }

    public function more( $hex , $percentage=100 )
    {
        list($red, $green, $blue) = self::hexRGB($hex);
        $this->_red->more( $red , $percentage );
        $this->_green->more( $green , $percentage );
        $this->_blue->more( $blue , $percentage );
        return $this;
    }

    public function setColor( $hex )
    {
        list($this->red, $this->green, $this->blue) = self::hexRGB($hex);
        return $this;
    }

    public function __set( $color , $value )
    {
        if( !in_array( $color, array('red','green','blue') ) ) return;
        $this->{'_'.$color}->setValue( $value );
    }

    public function &__get( $color )
    {
        if( !in_array( $color, array('red','green','blue') ) ) return;
        return $this->{'_'.$color};
    }

    public function __toString()
    {
        return '0x' . $this->_red . $this->_green . $this->_blue;
    }

    public static function hexRGB( $hex )
    {
        return array( $hex >> 16 & 0xFF , $hex >> 8 & 0xFF , $hex & 0xFF );
    }

}

function Color( $hex=0x000000 ) {
    return new Color( $hex );
}

希望有帮助!

编辑:刚刚赶上线程(在这样做之后),看到你想让 0xFFFF00 + 0x0000FF 变成绿色,而不是白色 - 叹息这不会那样做,它只适用于十六进制 rgb 颜色 - 抱歉!

于 2010-07-19T08:53:16.720 回答
2

混合颜色有很多不同的模型。我建议使用 RGBA 模型。

$colors = array(
    'opaque_green' => '00FF00FF',
    'transparent_blue' => '0000FF33',
);


public function toHex($red, $green, $blue, $alpha) {
    return sprintf("%02X%02X%02X%02X", $red, $green, $blue, $alpha);
}

//Reverted to british spelling :P
public function mixColours($colours) {
   $red = 0; $blue = 0; $green = 0; $alpha = 256; 
   foreach($colours as $colour) {
       $alpha_mod = hexdec(substr($colour, 6, 2)) / 256;
       $red   += $alpha_mod * hexdec(substr($colour, 0, 2));
       $green += $alpha_mod * hexdec(substr($colour, 2, 2));
       $blue  += $alpha_mod * hexdec(substr($colour, 4, 2));
   }
   $num_colours = count($colours);
   return toHex($red/$num_colours, $green/$num_colours, $blue/$num_colours, $alpha);
}

所以mixColours(array($colors['opaque_green'], $colors['transparent_blue']);应该给你一些浅绿色的 RGBA 十六进制字符串。

对于单词转换,您可以将颜色中的总光加起来并推断颜色是“暗”、“正常”还是“亮”。您还可以将色调设为“绿色”、“橙色”等,并建立一个词汇表来描述颜色。

于 2010-07-19T06:04:45.143 回答
2

我认为你能得到的最接近的是 CMY 颜色模型,幸运的是,它只是 RGB 的倒数。

C = 1 - R
M = 1 - G
Y = 1 - B

现在,如果您假设(尽管 CMY 是青色-品红色-黄色)C = 蓝色,M = 红色,Y = 黄色,那么您将非常接近您的艺术色彩。例如:

  • 蓝色变为 (1, 0, 0)
  • 黄色变为 (0, 0, 1)
  • 蓝色 + 黄色变为 (1, 0, 1)
  • 转换回 RGB 得到绿色的 (0, 1, 0)

更新:

0 到 1 只是方便表示无色和全色,相当于标准 RGB 的 0 到 255。

对于那些想知道“这显然是错误的,青色 = 蓝色如何?”的人,您还应该意识到 CMY != 艺术色彩。事实上,艺术色彩不匹配任何原色模型,所以这只是一个合理的假设,可以通过在艺术中混合颜料来获得你期望得到的那种颜色。

于 2010-07-19T06:17:19.877 回答
1

这里的主要问题是理解加色/减色的概念:

蓝色 + 黄色 = 绿色 仅适用于颜料(油漆、墨水等),因为它们是减色

如果您使用灯光(加色),您会得到:蓝色 + 黄色 = 白色

解决方案 ?如果你想描述减色(类似油漆的组合),你必须应用规则“互补色相加”:

blue(#0000FF) +sub yellow(#FFFF00) = black(#000000)
because
blue_complement(#FFFF00) +add yellow_complement(#0000FF) = #(FFFFFF) --> white which is black complement

(事实上​​我们会得到一些深棕色,因为颜料从来都不是完美的)那么为什么我们在现实生活中会变成绿色呢?因为我们不使用“蓝色”,而是使用青色(#00FFFF)和:

cyan(#00FFFF) +sub yellow(#FFFF00) = green(#00FF00)
because
cyan_complement(#FF0000) +add yellow_complement(#0000FF) = #(FF00FF) --> magenta 

我必须补充一点,这是描述颜色交互的一种非常简单的方式,但要复杂得多......

于 2010-07-19T11:50:30.393 回答
1

阅读减色原色,之后您可以阅读RYB 颜色模型

从 RYB 转换为 RGB 似乎不是那么容易,您可能需要检查这个计算器(以及它背后的 javascript)。

于 2010-07-19T08:24:42.933 回答
0
public function more($color, $percent = 100) {

    $percent = trim($percent, '% ');
    $percent /= 100;

    // Dictionary lookup that maps 'yellow' to #ffff00 and 'indianred' to #cd5c5c
    $color = $this->_map_color($color);

    // Creates a new Color - this will automatically compute RGB, CYM, HEX, and HSB color models
    $color = new Color($color);

    // $this->color is current color , $color is the color to be added to original

    // Allows hue to be both 360 degrees and 0 degrees
    if($this->color->hsb('h') == 0) {
        if($color->hsb('h') > 180) {
            $h = 360;
        } else {
            $h = 0;
        }
    } else {
        $h = $this->color->hsb('h');
    }

    // Computes weights of colors - original:addedColor
    // 100% added means perfect blend 50:50
    // 50% means 75:25
    // 0% means no color added 100:0
    $c2_weight = $percent / 2;
    $c1_weight = 1 - $c2_weight;

    // Compute the hue, saturation, brightness values using the weights
    $hsb[0] = round($c1_weight * $h + $c2_weight * $color->hsb('h'));
    $hsb[1] = round($c1_weight * $this->color->hsb('s') + $c2_weight * $color->hsb('s'));
    $hsb[2] = round($c1_weight * $this->color->hsb('b') + $c2_weight * $color->hsb('b'));

    $hsb = implode(' ', $hsb);

    // Change current color into the new computed HSB value.    
    $this->color = $this->color->hsb($hsb);

    return $this;
}

如果该方法需要更多解释,或者您在此处发现有问题,请告诉我!我必须说它工作得很好!我还会注意到这less($color, $percent)是相同的,只是你减去了颜色。Less 对我来说仍然没有直观意义(黄绿色 - 绿色 = 棕色),但我很确定计算是正确的。再次感谢你的帮助!

于 2010-07-19T21:15:16.307 回答