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