Смешивание цветов (добавление и вычитание цветов) как в Art Class! - PullRequest
3 голосов
/ 19 июля 2010

Я создаю цветовой класс и собираюсь добавлять операции больше (цвет, процент) и меньше (цвет, процент). Это требует умения добавлять и вычитать цвета, и мне сложно с арифметикой. Как использовать 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 * красный = желтый

EDIT: Хорошо, спасибо за ваш вклад. Я попытался добавить CYM друг к другу, к сожалению, красный (255, 0, 0) ~ = (0, 1, 1) в CYM, а затем, если вы добавите это на синий (0, 0, 255) ~ = (1, 1 , 0) он будет равен (1, 2, 1) или (1, 1, 1), который является черным в CYM.

Я получил самое близкое использование насыщенности оттенка Яркость (HSB). На самом деле это работает с каждой цветовой комбинацией, кроме красный портит. Я считаю это потому что красный в начале и конец оттенка (для оттенка используются градусы [0, 360]).

Буду признателен за любые ваши мысли!


РЕДАКТИРОВАТЬ 2:

Ладно, после вечера, проведенного без суеты, это "более" метод, которым я действительно доволен.

Используется цветовая модель HSB (Hue-Saturation-Brightness). Теперь не спрашивайте меня, почему я не работал CYM. Я цветной новичок. Похоже, что это будет работать, видя, как принтеры смешивают цвета. Мне очень нравится модель HSB, плюс то, что показывает фотошоп, когда вы используете палитру цветов.

Я добавил это как ответ, поэтому дайте мне знать, что вы, ребята, думаете! Еще раз спасибо!


Любая помощь будет отличной!

Спасибо, Matt

Ответы [ 7 ]

3 голосов
/ 19 июля 2010

Одним из решений, использующих цветовое пространство 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 - это несколько другая проблема.

2 голосов
/ 19 июля 2010

это было весело!

Примеры:

// 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 - извинения!

2 голосов
/ 19 июля 2010

Я думаю, что ближе всего вы можете получить цветовую модель 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 - это просто удобные представления без цвета и полного цвета, эквивалентные от 0 до 255 стандартного RGB.

Для тех, кто задается вопросом «это, очевидно, неправильно, как циан = синий?», Вы также должны понимать, что CMY! = Художественный цвет. На самом деле художественный цвет не соответствует ни одной основной цветовой модели, поэтому это разумное предположение, чтобы получить тот цвет, который вы ожидаете получить, смешивая краски в искусстве.

2 голосов
/ 19 июля 2010

Существует множество разных моделей для смешивания цветов. Я бы предложил модель 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 цвета морской волны.

Для преобразования слов вы можете суммировать общее количество света в цвете и определить, является ли цвет темным, нормальным или светлым. Вы также можете получить оттенок «зеленый», «оранжевый» и т. Д. И создать словарь для описания цвета.

1 голос
/ 19 июля 2010

Основной проблемой здесь является понимание концепции аддитивного / вычитающего цвета:

синий + желтый = зеленый только для пигментов (краски, чернила и т. Д.), Потому что они вычитающего цвета

если вы используете источники света ( аддитивные цвета ), вы получите: синий + желтый = белый

Решение? Если вы хотите описать субтрактивные цвета (подобие краски), вы должны применить правило «суммировать дополнительные цвета»:

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 

Я должен добавить, что это очень простой способ описания взаимодействия цвета, который намного сложнее ...

1 голос
/ 19 июля 2010

Прочитайте о субтрактивных праймериз , после чего вы можете прочитать о RYB цветовой модели .

Кажется, что преобразование из RYB в RGB не так просто, вы можете проверить этот калькулятор (и JavaScript за ним).

0 голосов
/ 20 июля 2010
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) то же самое, за исключением того, что вы вычли цвет вместо этого. Меньше все же не имеет для меня интуитивного смысла (желто-зеленый - зеленый = коричневый), но я почти уверен, что вычисления верны. Еще раз спасибо за вашу помощь!

...