3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

日本情報クリエイト EngineersAdvent Calendar 2016

Day 20

sassのlighten, darken, saturate, desaturateをphpで再現する

Posted at

sassの彩度・明度の調整をphpで再現しました。
下記サイトの計算式を参考にしています。
http://www.peko-step.com/tool/hslrgb.html

ColorChanger.php
<?php
class ColorChanger
{
    private $_r = 0, $_g = 0, $_b = 0, $_h = 0, $_s = 0, $_l = 0;

    public function lighten ($color, $lightness)
    {
        $this->setColor($color);
        $l = $this->_l;
        $l += $lightness;
        $this->_l = (100 < $l)?100:$l;
        $this->_getRgb();
        return $this->_decHex($this->_r) .  $this->_decHex($this->_g) .  $this->_decHex($this->_b);
    }

    public function darken ($color, $darkness)
    {
        $this->setColor($color);
        $l = $this->_l;
        $l -= $darkness;
        $this->_l = (0 > $l)?0:$l;
        $this->_getRgb();
        return $this->_decHex($this->_r) .  $this->_decHex($this->_g) .  $this->_decHex($this->_b);
    }

    public function saturate ($color, $per)
    {
        $this->setColor($color);
        $s = $this->_s;
        $s += $per;
        $this->_s = (100 < $s)?100:$s;
        $this->_getRgb();
        return $this->_decHex($this->_r) .  $this->_decHex($this->_g) .  $this->_decHex($this->_b);
    }

    public function desaturate ($color, $per)
    {
        $this->setColor($color);
        $s = $this->_s;
        $s -= $per;
        $this->_s = (0 > $s)?0:$s;
        $this->_getRgb();
        return $this->_decHex($this->_r) .  $this->_decHex($this->_g) .  $this->_decHex($this->_b);
    }

    public function _decHex ($dec)
    {
        return sprintf('%02s', dechex($dec));
    }

    private function setColor ($color)
    {
        $this->_r = hexdec(substr($color, 0, 2));
        $this->_g = hexdec(substr($color, 2, 2));
        $this->_b = hexdec(substr($color, 4, 2));
        $this->_maxRgb = max($this->_r, $this->_g, $this->_b);
        $this->_minRgb = min($this->_r, $this->_g, $this->_b);
        $this->_getHue();
        $this->_getSaturation();
        $this->_getLuminance();
    }

    private function _getHue ()
    {
        $r = $this->_r;
        $g = $this->_g;
        $b = $this->_b;
        $max = $this->_maxRgb;
        $min = $this->_minRgb;
        if ($r === $g && $r === $b) {
            $h = 0;
        } else {
            $mm = $max - $min;
            switch ($max) {
            case $r :
                $h = 60 * ($mm?($g - $b) / $mm:0);
                break;
            case $g :
                $h = 60 * ($mm?($b - $r) / $mm:0) + 120;
                break;
            case $b :
                $h = 60 * ($mm?($r - $g) / $mm:0) + 240;
                break;
            }
            if (0 > $h) {
                $h += 360;
            }
        }
        $this->_h = $h;
    }

    private function _getSaturation ()
    {
        $max = $this->_maxRgb;
        $min = $this->_minRgb;
        $cnt = round(($max + $min) / 2);
        if (127 >= $cnt) {
            $tmp = ($max + $min);
            $s = $tmp?($max - $min) / $tmp:0;
        } else {
            $tmp = (510 - $max - $min);
            $s = ($tmp)?(($max - $min) / $tmp):0;
        }
        $this->_s = $s * 100;
    }

    private function _getLuminance ()
    {
        $max = $this->_maxRgb;
        $min = $this->_minRgb;
        $this->_l = ($max + $min) / 2 / 255 * 100;
    }

    private function _getMaxMinHsl ()
    {
        $s = $this->_s;
        $l = $this->_l;
        if (49 >= $l) {
            $max = 2.55 * ($l + $l * ($s / 100));
            $min = 2.55 * ($l - $l * ($s / 100));
        } else {
            $max = 2.55 * ($l + (100 - $l) * ($s / 100));
            $min = 2.55 * ($l - (100 - $l) * ($s / 100));
        }
        $this->_maxHsl = $max;
        $this->_minHsl = $min;
    }

    private function _getRGB ()
    {
        $this->_getMaxMinHsl();
        $h = $this->_h;
        $s = $this->_s;
        $l = $this->_l;
        $max = $this->_maxHsl;
        $min = $this->_minHsl;
        if (60 >= $h) {
            $r = $max;
            $g = ($h / 60) * ($max - $min) + $min;
            $b = $min;
        } else if (120 >= $h) {
            $r = ((120 - $h) / 60) * ($max - $min) + $min;
            $g = $max;
            $b = $min;
        } else if (180 >= $h) {
            $r = $min;
            $g = $max;
            $b = (($h - 120) / 60) * ($max - $min) + $min;
        } else if (240 >= $h) {
            $r = $min;
            $g = ((240 - $h) / 60) * ($max - $min) + $min;
            $b = $max;
        } else if (300 >= $h) {
            $r = (($h - 240) / 60) * ($max - $min) + $min;
            $g = $min;
            $b = $max;
        } else {
            $r = $max;
            $g = $min;
            $b = ((360 - $h) / 60) * ($max - $min) + $min;
        }
        $this->_r = round($r);
        $this->_g = round($g);
        $this->_b = round($b);
    }
}
  • 使い方
test.php
<?php
include('plugins/NjcCommon/Lib/Color/ColorChanger.php');

$colorChanger = new ColorChanger();
$color = 'ff7700';
$val = 10;
echo "sass の lighten(#{$color}, {$val}%); -> " . $colorChanger->lighten($color, $val) . "\n";
echo "sass の darken(#{$color}, {$val}%); -> " . $colorChanger->darken($color, $val) . "\n";

$val = 50;
$color = 'bf7b40';
echo "sass の saturate(#{$color}, {$val}%); -> " . $colorChanger->saturate($color, $val) . "\n";
$color = 'ff7700';
echo "sass の desaturate(#{$color}, {$val}%); -> " . $colorChanger->desaturate($color, $val) . "\n";
  • 実行結果
$ php -f test.php 
sass の lighten(#ff7700, 10%); -> ff9233
sass の darken(#ff7700, 10%); -> cc5f00
sass の saturate(#bf7b40, 50%); -> ff7600
sass の desaturate(#ff7700, 50%); -> bf7b40
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?