1: <?php
2:
3: /**
4: * Jyxo PHP Library
5: *
6: * LICENSE
7: *
8: * This source file is subject to the new BSD license that is bundled
9: * with this package in the file license.txt.
10: * It is also available through the world-wide-web at this URL:
11: * https://github.com/jyxo/php/blob/master/license.txt
12: */
13:
14: namespace Jyxo;
15:
16: /**
17: * Class representing a RGB color.
18: *
19: * @category Jyxo
20: * @package Jyxo\Color
21: * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
22: * @license https://github.com/jyxo/php/blob/master/license.txt
23: * @author Roman Řáha
24: */
25: class Color
26: {
27: /**
28: * Minimal luminance.
29: *
30: * @var integer
31: */
32: const LUM_MIN = 0x00;
33:
34: /**
35: * Maximal luminance.
36: *
37: * @var integer
38: */
39: const LUM_MAX = 0xFF;
40:
41: /**
42: * The red component of the color.
43: *
44: * @var integer
45: */
46: private $red = self::LUM_MIN;
47:
48: /**
49: * The green component of the color.
50: *
51: * @var integer
52: */
53: private $green = self::LUM_MIN;
54:
55: /**
56: * The blue component of the color.
57: *
58: * @var integer
59: */
60: private $blue = self::LUM_MIN;
61:
62: /**
63: * Constructor.
64: *
65: * Accepts the following definition formats:
66: * * Hexadecimal string (with or without the hashmark at the beginning)
67: * * Array with red, green and blue component luminance values (in this order)
68: * * Number,
69: * * {@link \Jyxo\Color},
70: * * null
71: *
72: * @param mixed $color Color definition
73: */
74: public function __construct($color = null)
75: {
76: if (is_string($color)) {
77: $this->initFromHex($color);
78: } elseif (is_array($color)) {
79: $this->initFromRgb($color);
80: } elseif (is_int($color)) {
81: $this->initFromInt($color);
82: } elseif ($color instanceof self) {
83: $this->red = $color->getRed();
84: $this->green = $color->getGreen();
85: $this->blue = $color->getBlue();
86: }
87: }
88:
89: /**
90: * Returns an inverse color.
91: *
92: * @return \Jyxo\Color
93: */
94: public function toInverse()
95: {
96: $negative = new self();
97: // Subtracts color component values from the maximum luminance
98: $negative->setRed(self::LUM_MAX - $this->red)
99: ->setGreen(self::LUM_MAX - $this->green)
100: ->setBlue(self::LUM_MAX - $this->blue);
101: return $negative;
102: }
103:
104: /**
105: * Returns the currect color converted to grayscale.
106: *
107: * @return \Jyxo\Color
108: */
109: public function toGrayScale()
110: {
111: $gray = new self();
112: $gray->setLuminance($this->getLuminance());
113: return $gray;
114: }
115:
116: /**
117: * Returns textual (#RRGGBB) representation of the current color.
118: *
119: * @return string
120: */
121: public function __toString()
122: {
123: return '#' . $this->getHex();
124: }
125:
126: /**
127: * Returns the current color as an array of the red, green and blue components.
128: *
129: * @return array
130: */
131: public function getRgb()
132: {
133: return array(
134: $this->red,
135: $this->green,
136: $this->blue
137: );
138: }
139:
140: /**
141: * Returns the current color as a six-digit hexadecimal number.
142: *
143: * @return string
144: */
145: public function getHex()
146: {
147: return str_pad(dechex($this->red), 2, '0', STR_PAD_LEFT)
148: . str_pad(dechex($this->green), 2, '0', STR_PAD_LEFT)
149: . str_pad(dechex($this->blue), 2, '0', STR_PAD_LEFT);
150: }
151:
152: /**
153: * Returns the current color in binary form 0 - black, 1 - white).
154: *
155: * @return integer
156: */
157: public function getBinary()
158: {
159: // Black or white corresponds to the most significant bit value
160: $luminance = $this->getLuminance();
161: return $luminance >> 7;
162: }
163:
164: /**
165: * Returns the red component luminance.
166: *
167: * @return integer
168: */
169: public function getRed()
170: {
171: return $this->red;
172: }
173:
174: /**
175: * Sets the red component luminance.
176: *
177: * @param integer|string $red Component luminance
178: * @return \Jyxo\Color
179: */
180: public function setRed($red)
181: {
182: $this->red = $this->toInt($red);
183: return $this;
184: }
185:
186: /**
187: * Returns the green component luminance.
188: *
189: * @return integer
190: */
191: public function getGreen()
192: {
193: return $this->green;
194: }
195:
196: /**
197: * Sets the green component luminance.
198: *
199: * @param integer|string $green Component luminance
200: * @return \Jyxo\Color
201: */
202: public function setGreen($green)
203: {
204: $this->green = $this->toInt($green);
205: return $this;
206: }
207:
208: /**
209: * Returns the blue component luminance.
210: *
211: * @return integer
212: */
213: public function getBlue()
214: {
215: return $this->blue;
216: }
217:
218: /**
219: * Sets the blue component luminance.
220: *
221: * @param integer|string $blue Component luminance
222: * @return \Jyxo\Color
223: */
224: public function setBlue($blue)
225: {
226: $this->blue = $this->toInt($blue);
227: return $this;
228: }
229:
230: /**
231: * Returns the color luminance according to the human perception.
232: *
233: * @return integer
234: */
235: public function getLuminance()
236: {
237: $luminance = 0.11 * $this->red + 0.59 * $this->green + 0.3 * $this->blue;
238: return (integer) floor($luminance);
239: }
240:
241: /**
242: * Sets the color in grayscale according to the luminance value.
243: *
244: * @param integer|string $luminance Luminance
245: * @return \Jyxo\Color
246: */
247: public function setLuminance($luminance)
248: {
249: $luminance = $this->toInt($luminance);
250: $this->red = $luminance;
251: $this->green = $luminance;
252: $this->blue = $luminance;
253: return $this;
254: }
255:
256: /**
257: * Sets color components using a hexadecimal RRGGBB string.
258: *
259: * @param string $hex Color definition
260: * @return \Jyxo\Color
261: * @throws \InvalidArgumentException If an invalid hexadecimal definition was provided
262: */
263: private function initFromHex($hex)
264: {
265: // Trim the hashmark if present
266: $hex = ltrim($hex, '#');
267:
268: if (strlen($hex) == 3) {
269: // RGB format support
270: $hex = $hex{0} . $hex{0} . $hex{1} . $hex{1} . $hex{2} . $hex{2};
271: }
272:
273: if (!preg_match('~[a-f0-9]{6}~i', $hex)) {
274: // Invalid color definition
275: throw new \InvalidArgumentException(sprintf('"%s" in not a valid hexadecimal color definition', $hex));
276: }
277:
278: $this->initFromInt(hexdec($hex));
279: return $this;
280: }
281:
282: /**
283: * Sets color components from an array.
284: *
285: * @param array $rgb Color definition
286: * @return \Jyxo\Color
287: */
288: private function initFromRgb(array $rgb)
289: {
290: $this->setRed($rgb[0])
291: ->setGreen($rgb[1])
292: ->setBlue($rgb[2]);
293: return $this;
294: }
295:
296: /**
297: * Sets color components from an integer.
298: *
299: * @param integer $int Color definition
300: * @return \Jyxo\Color
301: */
302: private function initFromInt($int)
303: {
304: $int = min(array($int, 0xFFFFFF));
305: $this->red = self::LUM_MAX & ($int >> 16);
306: $this->green = self::LUM_MAX & ($int >> 8);
307: $this->blue = self::LUM_MAX & $int;
308: return $this;
309: }
310:
311: /**
312: * Returns the color luminance as a decimal integer.
313: *
314: * @param integer|string $value Luminance value
315: * @return integer
316: */
317: private function toInt($value)
318: {
319: if (is_string($value)) {
320: $value = hexdec($value);
321: }
322: // Luminance must not be greater than 0xFF
323: return min(array((integer) $value, self::LUM_MAX));
324: }
325: }
326: