1<?php
2
3namespace Intervention\Image\Gd;
4
5use Intervention\Image\AbstractColor;
6use Intervention\Image\Exception\NotSupportedException;
7
8class Color extends AbstractColor
9{
10    /**
11     * RGB Red value of current color instance
12     *
13     * @var int
14     */
15    public $r;
16
17    /**
18     * RGB Green value of current color instance
19     *
20     * @var int
21     */
22    public $g;
23
24    /**
25     * RGB Blue value of current color instance
26     *
27     * @var int
28     */
29    public $b;
30
31    /**
32     * RGB Alpha value of current color instance
33     *
34     * @var float
35     */
36    public $a;
37
38    /**
39     * Initiates color object from integer
40     *
41     * @param  int $value
42     * @return \Intervention\Image\AbstractColor
43     */
44    public function initFromInteger($value)
45    {
46        $this->a = ($value >> 24) & 0xFF;
47        $this->r = ($value >> 16) & 0xFF;
48        $this->g = ($value >> 8) & 0xFF;
49        $this->b = $value & 0xFF;
50    }
51
52    /**
53     * Initiates color object from given array
54     *
55     * @param  array $value
56     * @return \Intervention\Image\AbstractColor
57     */
58    public function initFromArray($array)
59    {
60        $array = array_values($array);
61
62        if (count($array) == 4) {
63
64            // color array with alpha value
65            list($r, $g, $b, $a) = $array;
66            $this->a = $this->alpha2gd($a);
67
68        } elseif (count($array) == 3) {
69
70            // color array without alpha value
71            list($r, $g, $b) = $array;
72            $this->a = 0;
73
74        }
75
76        $this->r = $r;
77        $this->g = $g;
78        $this->b = $b;
79    }
80
81    /**
82     * Initiates color object from given string
83     *
84     * @param  string $value
85     * @return \Intervention\Image\AbstractColor
86     */
87    public function initFromString($value)
88    {
89        if ($color = $this->rgbaFromString($value)) {
90            $this->r = $color[0];
91            $this->g = $color[1];
92            $this->b = $color[2];
93            $this->a = $this->alpha2gd($color[3]);
94        }
95    }
96
97    /**
98     * Initiates color object from given R, G and B values
99     *
100     * @param  int $r
101     * @param  int $g
102     * @param  int $b
103     * @return \Intervention\Image\AbstractColor
104     */
105    public function initFromRgb($r, $g, $b)
106    {
107        $this->r = intval($r);
108        $this->g = intval($g);
109        $this->b = intval($b);
110        $this->a = 0;
111    }
112
113    /**
114     * Initiates color object from given R, G, B and A values
115     *
116     * @param  int     $r
117     * @param  int     $g
118     * @param  int     $b
119     * @param  float   $a
120     * @return \Intervention\Image\AbstractColor
121     */
122    public function initFromRgba($r, $g, $b, $a = 1)
123    {
124        $this->r = intval($r);
125        $this->g = intval($g);
126        $this->b = intval($b);
127        $this->a = $this->alpha2gd($a);
128    }
129
130    /**
131     * Initiates color object from given ImagickPixel object
132     *
133     * @param  ImagickPixel $value
134     * @return \Intervention\Image\AbstractColor
135     */
136    public function initFromObject($value)
137    {
138        throw new NotSupportedException(
139            "GD colors cannot init from ImagickPixel objects."
140        );
141    }
142
143    /**
144     * Calculates integer value of current color instance
145     *
146     * @return int
147     */
148    public function getInt()
149    {
150        return ($this->a << 24) + ($this->r << 16) + ($this->g << 8) + $this->b;
151    }
152
153    /**
154     * Calculates hexadecimal value of current color instance
155     *
156     * @param  string $prefix
157     * @return string
158     */
159    public function getHex($prefix = '')
160    {
161        return sprintf('%s%02x%02x%02x', $prefix, $this->r, $this->g, $this->b);
162    }
163
164    /**
165     * Calculates RGB(A) in array format of current color instance
166     *
167     * @return array
168     */
169    public function getArray()
170    {
171        return [$this->r, $this->g, $this->b, round(1 - $this->a / 127, 2)];
172    }
173
174    /**
175     * Calculates RGBA in string format of current color instance
176     *
177     * @return string
178     */
179    public function getRgba()
180    {
181        return sprintf('rgba(%d, %d, %d, %.2F)', $this->r, $this->g, $this->b, round(1 - $this->a / 127, 2));
182    }
183
184    /**
185     * Determines if current color is different from given color
186     *
187     * @param  AbstractColor $color
188     * @param  int       $tolerance
189     * @return boolean
190     */
191    public function differs(AbstractColor $color, $tolerance = 0)
192    {
193        $color_tolerance = round($tolerance * 2.55);
194        $alpha_tolerance = round($tolerance * 1.27);
195
196        $delta = [
197            'r' => abs($color->r - $this->r),
198            'g' => abs($color->g - $this->g),
199            'b' => abs($color->b - $this->b),
200            'a' => abs($color->a - $this->a)
201        ];
202
203        return (
204            $delta['r'] > $color_tolerance or
205            $delta['g'] > $color_tolerance or
206            $delta['b'] > $color_tolerance or
207            $delta['a'] > $alpha_tolerance
208        );
209    }
210
211    /**
212     * Convert rgba alpha (0-1) value to gd value (0-127)
213     *
214     * @param  float $input
215     * @return int
216     */
217    private function alpha2gd($input)
218    {
219        $oldMin = 0;
220        $oldMax = 1;
221
222        $newMin = 127;
223        $newMax = 0;
224
225        return ceil(((($input- $oldMin) * ($newMax - $newMin)) / ($oldMax - $oldMin)) + $newMin);
226    }
227}
228