Overview

Packages

  • AlfredBundler
  • None

Classes

  • AlfredBundler
  • AlfredBundlerIcon
  • AlfredBundlerInternalClass
  • AlfredBundlerLogger
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: 
   3: /**
   4:  * Alfred Bundler Icon and Color API file
   5:  *
   6:  * Interface for downloading, loading, and manipulating image resources to
   7:  * be used with the PHP implementation of the Alfred Bundler.
   8:  *
   9:  * This file is part of the Alfred Bundler, released under the MIT licence.
  10:  * Copyright (c) 2014 The Alfred Bundler Team
  11:  * See https://github.com/shawnrice/alfred-bundler for more information
  12:  *
  13:  * @copyright  The Alfred Bundler Team 2014
  14:  * @license    http://opensource.org/licenses/MIT  MIT
  15:  * @version    Taurus 1
  16:  * @link       http://shawnrice.github.io/alfred-bundler
  17:  * @package    AlfredBundler
  18:  * @since      File available since Taurus 1
  19:  */
  20: 
  21: if ( ! class_exists( 'AlfredBundlerIcon' ) ) :
  22: /**
  23:  *
  24:  * A class used to get / manipulate icons...
  25:  *
  26:  * @package AlfredBundler
  27:  * @since   Class available since Taurus 1
  28:  * @TODO document further
  29:  */
  30: class AlfredBundlerIcon {
  31: 
  32:   public  $background;
  33:   public  $data;
  34:   public  $cache;
  35: 
  36: 
  37:   /**
  38:    * Sets the variables to deal with icons
  39:    *
  40:    * @todo decide exactly where the cache is going to live
  41:    *
  42:    * @since Taurus 1
  43:    *
  44:    * @param  object  $bundler   the bundler object that instantiates this
  45:    */
  46:   public function __construct( $bundler ) {
  47: 
  48:     $this->mime       = finfo_open( FILEINFO_MIME_TYPE );
  49:     $this->bundler    = $bundler; // in case we need any of the variables...
  50:     $this->data       = $this->bundler->data;
  51:     // $this->cache      = $cache;
  52:     $this->colors     = array();
  53:     $this->fallback   = $this->data . '/bundler/meta/icons/default.png';
  54: 
  55:     $this->setBackground();
  56: 
  57:     $this->cache = $bundler->cache . '/color';
  58: 
  59:   }
  60: 
  61: 
  62: 
  63: /*****************************************************************************
  64:  * BEGIN SETUP FUNCTIONS
  65:  ****************************************************************************/
  66: 
  67:   /**
  68:    * Creates necessary folders for icons
  69:    *
  70:    * @since Taurus 1
  71:    *
  72:    */
  73:   private function setup() {
  74: 
  75:     if ( ! file_exists( $this->data . '/data' ) )
  76:       mkdir( $this->data . '/data' );
  77: 
  78:     if ( ! file_exists( $this->cache ) )
  79:       mkdir( $this->cache, 0775, TRUE );
  80: 
  81:   }
  82: 
  83: 
  84:   /**
  85:    * Set the 'background' variable to either 'light' or 'dark'
  86:    *
  87:    * As of Alfred v2.4 Build 277, environmental variables are available that
  88:    * expose the color of the theme background as sRGBa. If those variables
  89:    * are accessible, then we set the background with them.
  90:    *
  91:    * Otherwise, we fallback to a utility that comes with the bundler called
  92:    * 'LightOrDark' that reads the NSColor Object in the plist that Alfred
  93:    * uses to store the themes, and then it returns the value 'light' or 'dark'.
  94:    *
  95:    * @link [http://www.alfredforum.com/topic/4716-some-new-alfred-script-environment-variables-coming-in-alfred-24/] [Alfred 2.4 Environmental Variables]
  96:    *
  97:    * @since Taurus 1
  98:    *
  99:    */
 100:   private function setBackground() {
 101: 
 102:     if ( isset( $_ENV[ 'alfred_version' ] ) ) {
 103:       // Current Version >= v2.4:277
 104:       $this->setBackgroundFromEnv();
 105:     } else {
 106:       // Current Version < v2.4:277 -- or -- no env vars are set. Maybe
 107:       // you're running this outside of Alfred, eh?
 108:       $this->setBackgroundFromUtil();
 109:     }
 110:     // Make sure we've set the background
 111:     $this->validateBackground();
 112: 
 113:   }
 114: 
 115:   /**
 116:    * Sets the background to 'light' or 'dark' based on environmental variables
 117:    * based on a luminance calculation
 118:    *
 119:    * @see setBackground()
 120:    * @see setBackgroundFromUtil()
 121:    * @see getLuminance()
 122:    *
 123:    * @since Taurus 1
 124:    *
 125:    */
 126:   private function setBackgroundFromEnv() {
 127:     $pattern = "/rgba\(([0-9]{1,3}),([0-9]{1,3}),([0-9]{1,3}),([0-9.]{4,})\)/";
 128:     preg_match_all( $pattern, $_ENV[ 'alfred_theme_background' ], $matches );
 129: 
 130:     $this->background = $this->getLuminance(  array( 'r' => $matches[1][0],
 131:                                                      'g' => $matches[2][0],
 132:                                                      'b' => $matches[3][0] ) );
 133: 
 134:   }
 135: 
 136: 
 137:   /**
 138:    * Sets the theme background color to either 'light' or 'dark'
 139:    *
 140:    * This function checks for the existence of a file and considers the contents
 141:    * versus the modified time of the Alfredpreferences.plist where theme info
 142:    * is stored. If necessary, it uses a utility to determine the 'light/dark'
 143:    * status of the current Alfred theme. This method exists for versions of
 144:    * Alfred pre 2.4 build 277.
 145:    *
 146:    * @see setBackground()
 147:    * @see setBackgroundFromEnv()
 148:    *
 149:    * @since  Taurus 1
 150:    *
 151:    */
 152:   private function setBackgroundFromUtil() {
 153: 
 154:     // The Alfred preferences plist where the theme information is stored
 155:     $plist = "{$_SERVER[ 'HOME' ]}/Library/Preferences/com.runningwithcrayons.Alfred-Preferences.plist";
 156:     $cache = "{$this->data}/cache/misc/theme_background";
 157:     $util  = "{$this->data}/bundler/includes/LightOrDark";
 158: 
 159:     if ( ! file_exists( "{$this->data}/data" ) ) {
 160:       mkdir( "{$this->data}/data", 0775, TRUE );
 161:     }
 162: 
 163:     if ( file_exists( $cache ) ) {
 164:       if ( filemtime( $cache ) > filemtime( $plist ) ) {
 165:         $this->background = file_get_contents( $cache );
 166:         return TRUE;
 167:       }
 168:     }
 169: 
 170:     if ( file_exists( $util ) ) {
 171:       $this->background = exec( "'$util'" );
 172:       file_put_contents( $cache, $this->background );
 173:     } else {
 174:       $this->background = 'dark';
 175:     }
 176: 
 177:   }
 178: 
 179: 
 180:   /**
 181:    * Sets the theme background to dark if it isn't set
 182:    *
 183:    * @see setBackground()
 184:    *
 185:    * @since Taurus 1
 186:    */
 187:   public function validateBackground() {
 188: 
 189:     if ( ! isset( $this->background ) )
 190:       $this->background = 'dark';
 191: 
 192:     if ( $this->background != 'light' && $this->background != 'dark' )
 193:       $this->background = 'dark';
 194: 
 195:   }
 196: 
 197: 
 198: /*****************************************************************************
 199:  * END SETUP FUNCTIONS
 200:  ****************************************************************************/
 201: 
 202: /*****************************************************************************
 203:  * BEGIN ICON FUNCTIONS
 204:  ****************************************************************************/
 205: 
 206:   /**
 207:    * Returns a path to an icon
 208:    *
 209:    * @link [http://icons.deanishe.net] [Icon server documentation]
 210:    *
 211:    * @see parseIconArguments()
 212:    * @see getSystemIcon()
 213:    * @see getIcon()
 214:    * @see downloadIcon()
 215:    * @see tryServers()
 216:    * @see validateImage()
 217:    * @see color()
 218:    * @see prepareIcon()
 219:    *
 220:    * @since Taurus 1
 221:    *
 222:    * @param   array  $args  Associative array that evaluates to
 223:    *                        [ 'font' => font,
 224:    *                          'name' => icon-name,
 225:    *                          'color' => hex-color,
 226:    *                          'alter' => hex-color|bool ].
 227:    *                        The first two are mandatory; color defaults to
 228:    *                        '000000', and alter defaults to FALSE.
 229:    *
 230:    * @return  mixed         FALSE on user error, and file path on success
 231:    */
 232:   public function icon( $args ) {
 233: 
 234:     if ( count( $args ) < 2 )
 235:       return FALSE;
 236: 
 237:     if ( ! $args = $this->parseIconArguments( $args ) )
 238:       return FALSE;
 239: 
 240:     // Return system icon or fallback
 241:     if ( $args[ 'font' ] == 'system' )
 242:       return $this->getSystemIcon( $args[ 'name' ] );
 243: 
 244:     $args = $this->prepareIcon( $args );
 245: 
 246:     $dir  = "{$this->data}/data/assets/icons";
 247:     $icon = implode( '/', [ $dir, $args[ 'font' ], $args[ 'color' ], $args[ 'name' ] ] );
 248: 
 249:     if ( file_exists( $icon . '.png' ) ) {
 250:       return $icon . '.png';
 251:     }
 252: 
 253:     if ( $this->getIcon( $args ) ) {
 254:       return $icon . '.png';
 255:     }
 256: 
 257:     return $this->fallback;
 258: 
 259:   }
 260: 
 261: 
 262:   /**
 263:    * Validates and normalizes the arguments for the icon method
 264:    *
 265:    * @see icon()
 266:    *
 267:    * @since Taurus 1
 268:    *
 269:    * @param  array  $args  the arguments passed to icon()
 270:    *
 271:    * @return  array         a normalized version of the input
 272:    */
 273:   private function parseIconArguments( $args ) {
 274: 
 275:     $args[ 'font' ] = strtolower( trim( $args[ 'font' ] ) );
 276:     if ( ! isset( $args[ 'alter' ] ) ) {
 277:       $args[ 'alter' ] = FALSE;
 278:     }
 279:     if ( ! isset( $args[ 'color' ] ) ) {
 280:       $args[ 'color' ] = '000000';
 281:       $args[ 'alter' ] = TRUE;
 282:     }
 283:     return $args;
 284: 
 285:   }
 286: 
 287: 
 288:   /**
 289:    * Fetches a system icon path
 290:    *
 291:    * @since Taurus 1
 292:    *
 293:    * @param   string  $name  name of a system icon (with no extension)
 294:    *
 295:    * @return  string         path to system icon or fallback
 296:    */
 297:   private function getSystemIcon( $name ) {
 298: 
 299:     $icon = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/{$name}.icns";
 300: 
 301:     if ( file_exists( $icon ) )
 302:       return $icon;
 303: 
 304:     return "{$this->data}/bundler/meta/icons/default.icns";
 305:   }
 306: 
 307: 
 308:   /**
 309:    * Queries server to download non-local icon
 310:    *
 311:    * @see icon()
 312:    *
 313:    * @since Taurus 1
 314:    *
 315:    * @param   array  $args  Same args as icon()
 316:    *
 317:    * @return  string        Path to icon or fallback
 318:    */
 319:   public function getIcon( $args ) {
 320: 
 321:     $dir = implode( '/' , [ $this->data, 'data', 'assets', 'icons', $args[ 'font' ], $args[ 'color' ] ] );
 322: 
 323:     if ( ! file_exists( $dir ) )
 324:       mkdir( $dir, 0775, TRUE );
 325: 
 326:     $icon = $dir . '/' . $args[ 'name' ];
 327: 
 328:     $suburl = implode( '/', [ 'icon', $args[ 'font' ], $args[ 'color' ], $args[ 'name' ] ] );
 329:     $success = $this->tryServers( $suburl, $icon );
 330: 
 331:     // If success is true, then we downloaded the icon
 332:     if ( $success !== TRUE ) {
 333:       unlink( $icon . '.png' );
 334:       return FALSE;
 335:     }
 336: 
 337:     if ( $this->validateImage( $icon ) ) {
 338:       return $icon . '.png';
 339:     }
 340: 
 341:     // log error here
 342:     unlink( $icon . '.png' );
 343:     return $this->fallback;
 344: 
 345:   }
 346: 
 347: 
 348:   /**
 349:    * Cycles through a list of servers to download an icon
 350:    *
 351:    * The method tries to get the icon from the first server,
 352:    * if the server is unreachable, then it will go down the
 353:    * list until it succeeds. If none are available, then it
 354:    * reports its failure.
 355:    *
 356:    * @see     icon()
 357:    * @see     getIcon()
 358:    * @see     downloadIcon()
 359:    *
 360:    * @since   Taurus 1
 361:    *
 362:    * @param   array   $args   associative array containing suburl
 363:    *                          arguments: font, name, color
 364:    * @param   string  $icon   filepath to icon destination
 365:    *
 366:    * @return  bool          TRUE on success, FALSE on failure
 367:    */
 368:   public function tryServers( $args, $icon ) {
 369: 
 370:     $servers = explode( PHP_EOL, file_get_contents( $this->data . "/bundler/meta/icon_servers" ) );
 371: 
 372:     // Cycle through the servers until we find one that is up.
 373:     foreach ( $servers as $server ) :
 374:       $url = $server . '/' . $args;
 375:       $status = $this->downloadIcon( $url, $icon );
 376:       if ( $status === 0 )
 377:         return TRUE;
 378:     endforeach;
 379: 
 380:     //logerrorhere
 381:     return FALSE;
 382: 
 383:   }
 384: 
 385: 
 386:   /**
 387:    * Downloads an icon from a server
 388:    *
 389:    * @see     icon()
 390:    * @see     getIcon()
 391:    * @see     tryServers()
 392:    *
 393:    * @since   Taurus 1
 394:    *
 395:    * @param   string  $url   url to file
 396:    * @param   string  $icon  path to file destination
 397:    *
 398:    * @return  int            cURL exit status
 399:    */
 400:   public function downloadIcon( $url, $icon ) {
 401: 
 402:     $c = curl_init( $url );
 403:     $f = fopen( $icon . '.png', "w" );
 404:     curl_setopt_array( $c, array(
 405:           CURLOPT_FILE => $f,
 406:           CURLOPT_HEADER => FALSE,
 407:           CURLOPT_FOLLOWLOCATION => TRUE,
 408:           CURLOPT_CONNECTTIMEOUT => 2 ) );
 409: 
 410:     curl_exec( $c );
 411:     fclose( $f );
 412: 
 413:     $status = curl_errno( $c );
 414:     $info = curl_getinfo($c);
 415: 
 416:     if ( $info[ 'http_code' ] !== 200 ) {
 417:       // Log the error somehow here to show that it's not a good deal, yo.
 418:       $status = 404;
 419:     }
 420: 
 421:     curl_close( $c );
 422: 
 423:     return $status;
 424: 
 425:   }
 426: 
 427: 
 428:   /**
 429:    * Checks a file to see if it is a png.
 430:    *
 431:    * @since   Taurus 1
 432:    *
 433:    * @param   string  $image  file path to alleged image
 434:    *
 435:    * @return  bool            TRUE is a png, FALSE if not
 436:    */
 437:   public function validateImage( $image ) {
 438:     if ( finfo_file( $this->mime, $image . '.png' ) == 'image/png' )
 439:       return TRUE;
 440:     return FALSE;
 441: 
 442:   }
 443: 
 444: /*****************************************************************************
 445:  * END ICON FUNCTIONS
 446:  ****************************************************************************/
 447: 
 448: 
 449: 
 450: /*****************************************************************************
 451:  * BEGIN COLOR FUNCTIONS
 452:  ****************************************************************************/
 453: 
 454:   /**
 455:    * Normalizes and validates a color and adds it to the color array
 456:    *
 457:    * @see     prepareIcon()
 458:    * @see     checkHex()
 459:    * @see     validateHex()
 460:    * @see     normalizeHex()
 461:    * @see     rgb()
 462:    * @see     hsv()
 463:    * @see     luminance()
 464:    * @see     brightness()
 465:    * @see     altered()
 466:    * @see     hexToRgb()
 467:    * @see     rgbToHex()
 468:    * @see     rgbToHsv()
 469:    * @see     hsvToRgb()
 470:    * @see     alter()
 471:    * @see     getLuminance()
 472:    * @see     getBrightness()
 473:    *
 474:    * @since   Taurus 1
 475:    *
 476:    * @param   string  $color  a hex color
 477:    *
 478:    * @return  string          a hex normalized and validated hex color
 479:    */
 480:   public function color( $color ) {
 481: 
 482:     if ( ! in_array( $color, $this->colors ) ) {
 483:       if ( ! $color = $this->checkHex( $color ) )
 484:         return FALSE;
 485:       $this->colors[ $color ][ 'hex' ] = $color;
 486:     }
 487:     return $color;
 488: 
 489:   }
 490: 
 491:   /**
 492:    * Prepares the icon arguments for a proper query
 493:    *
 494:    * The color is first normalized. Then, if the `alter` variable
 495:    * has not been set, then it just send the arguments back. Otherwise
 496:    * a check is run to see if the theme background color is
 497:    * the same as the proposed icon color. If not, then it sends back
 498:    * the arguments. If so, then, if the `alter` variable is another
 499:    * hex color, it returns that. If, instead, it is TRUE, then alters
 500:    * the color accordingly so that the icon will best appear on
 501:    * the background.
 502:    *
 503:    * @see     icon()
 504:    * @see     color()
 505:    * @see     checkHex()
 506:    * @see     validateHex()
 507:    * @see     normalizeHex()
 508:    * @see     rgb()
 509:    * @see     hsv()
 510:    * @see     luminance()
 511:    * @see     brightness()
 512:    * @see     altered()
 513:    * @see     hexToRgb()
 514:    * @see     rgbToHex()
 515:    * @see     rgbToHsv()
 516:    * @see     hsvToRgb()
 517:    * @see     alter()
 518:    * @see     getLuminance()
 519:    * @see     getBrightness()
 520:    *
 521:    * @since   Taurus 1
 522:    *
 523:    * @param   array  $args  an associative array of args passed to icon()
 524:    *
 525:    * @return  array         possible altered array of args to load an icon
 526:    */
 527:   public function prepareIcon( $args ) {
 528: 
 529:     $args[ 'color' ] = $this->color( $args[ 'color' ] );
 530: 
 531:     if ( $args[ 'alter' ] === FALSE )
 532:       return $args;
 533: 
 534:     if ( $this->brightness( $args[ 'color' ] ) != $this->background )
 535:       return $args;
 536: 
 537: 
 538:     if ( ! is_bool( $args[ 'alter' ] ) ) {
 539:       if ( ! $args[ 'color' ] = $this->color( $args[ 'alter' ] ) )
 540:         $args[ 'color' ] = '000000';
 541: 
 542:       return $args;
 543:     }
 544:     $args[ 'color' ] = $this->altered( $args[ 'color' ] );
 545:     return $args;
 546: 
 547:   }
 548: 
 549: 
 550: /*****************************************************************************
 551:  * BEGIN GETTER FUNCTIONS  (well, we set when not already set)
 552:  ****************************************************************************/
 553: 
 554:   /**
 555:    * Returns the RGB of a color, and it sets it if necessary
 556:    *
 557:    * @see     color()
 558:    * @see     prepareIcon()
 559:    * @see     checkHex()
 560:    * @see     validateHex()
 561:    * @see     normalizeHex()
 562:    * @see     hsv()
 563:    * @see     luminance()
 564:    * @see     brightness()
 565:    * @see     altered()
 566:    * @see     hexToRgb()
 567:    * @see     rgbToHex()
 568:    * @see     rgbToHsv()
 569:    * @see     hsvToRgb()
 570:    * @see     alter()
 571:    * @see     getLuminance()
 572:    * @see     getBrightness()
 573:    *
 574:    * @since   Taurus 1
 575:    *
 576:    * @param   string  $color  hex color
 577:    *
 578:    * @return  array           associative array of RGB values
 579:    */
 580:   public function rgb( $color ) {
 581: 
 582:     if ( ! isset( $this->colors[ $color ][ 'rgb' ] ) ) {
 583:       $this->colors[ $color ][ 'rgb' ] = $this->hexToRgb( $color );
 584:     }
 585:     return $this->colors[ $color ][ 'rgb' ];
 586: 
 587:   }
 588: 
 589: 
 590: 
 591:   /**
 592:    * Returns the HSV of a color, and it sets it if necessary
 593:    *
 594:    * @link [https://en.wikipedia.org/wiki/HSL_and_HSV] [color forumulas]
 595:    *
 596:    * @see     color()
 597:    * @see     prepareIcon()
 598:    * @see     checkHex()
 599:    * @see     validateHex()
 600:    * @see     normalizeHex()
 601:    * @see     rgb()
 602:    * @see     luminance()
 603:    * @see     brightness()
 604:    * @see     altered()
 605:    * @see     hexToRgb()
 606:    * @see     rgbToHex()
 607:    * @see     rgbToHsv()
 608:    * @see     hsvToRgb()
 609:    * @see     alter()
 610:    * @see     getLuminance()
 611:    * @see     getBrightness()
 612:    *
 613:    * @since   Taurus 1
 614:    *
 615:    * @param   string  $color  hex color
 616:    *
 617:    * @return  array          associative array of HSV values
 618:    */
 619:   public function hsv( $color ) {
 620: 
 621:     if ( ! isset( $this->colors[ $color ][ 'hsv' ] ) ) {
 622:       if ( ! isset( $this->colors[ $color ][ 'rgb' ] ) ) {
 623:         $this->rgb( $color );
 624:       }
 625:       $this->colors[ $color ][ 'hsv' ] = $this->rgbToHsv( $this->rgb( $color ) );
 626:     }
 627:     return $this->colors[ $color ][ 'hsv' ];
 628: 
 629:   }
 630: 
 631: 
 632:   /**
 633:    * Retrieves the altered color of the original
 634:    *
 635:    * @see     color()
 636:    * @see     prepareIcon()
 637:    * @see     checkHex()
 638:    * @see     validateHex()
 639:    * @see     normalizeHex()
 640:    * @see     rgb()
 641:    * @see     hsv()
 642:    * @see     luminance()
 643:    * @see     brightness()
 644:    * @see     hexToRgb()
 645:    * @see     rgbToHex()
 646:    * @see     rgbToHsv()
 647:    * @see     hsvToRgb()
 648:    * @see     alter()
 649:    * @see     getLuminance()
 650:    * @see     getBrightness()
 651:    *
 652:    * @since   Taurus 1
 653:    *
 654:    * @param   string  $color  a hex color
 655:    *
 656:    * @return  string          a hex color (lighter or darker than the original)
 657:    */
 658:   public function altered( $color ) {
 659: 
 660:     if ( ! isset( $this->colors[ $color ][ 'altered' ] ) ) {
 661:       if ( ! $this->colors[ $color ][ 'altered' ] = $this->cached( $color ) )
 662:         $this->colors[ $color ][ 'altered' ] = $this->alter( $color );
 663:     }
 664:     return $this->colors[ $color ][ 'altered' ];
 665: 
 666:   }
 667: 
 668: 
 669: 
 670:   /**
 671:    * Retrieves the luminance of a hex color
 672:    *
 673:    * @see     color()
 674:    * @see     prepareIcon()
 675:    * @see     checkHex()
 676:    * @see     validateHex()
 677:    * @see     normalizeHex()
 678:    * @see     rgb()
 679:    * @see     hsv()
 680:    * @see     brightness()
 681:    * @see     altered()
 682:    * @see     hexToRgb()
 683:    * @see     rgbToHex()
 684:    * @see     rgbToHsv()
 685:    * @see     hsvToRgb()
 686:    * @see     alter()
 687:    * @see     getLuminance()
 688:    * @see     getBrightness()
 689:    *
 690:    * @since Taurus 1
 691:    *
 692:    * @param   string  $color  a hex color
 693:    *
 694:    * @return  float           the luminance between 0 and 1
 695:    */
 696:   public function luminance( $color ) {
 697: 
 698:     if ( ! isset( $this->colors[ $color ][ 'luminance' ] ) ) {
 699:       $this->colors[ $color ][ 'luminance' ] = $this->getLuminance( $color );
 700:     }
 701:     return $this->colors[ $color ][ 'luminance' ];
 702: 
 703:   }
 704: 
 705: 
 706:   /**
 707:    * Queries whether and image is 'light' or 'dark'
 708:    *
 709:    * @see     color()
 710:    * @see     prepareIcon()
 711:    * @see     checkHex()
 712:    * @see     validateHex()
 713:    * @see     normalizeHex()
 714:    * @see     rgb()
 715:    * @see     hsv()
 716:    * @see     luminance()
 717:    * @see     altered()
 718:    * @see     hexToRgb()
 719:    * @see     rgbToHex()
 720:    * @see     rgbToHsv()
 721:    * @see     hsvToRgb()
 722:    * @see     alter()
 723:    * @see     getLuminance()
 724:    * @see     getBrightness()
 725:    *
 726:    * @since   Taurus 1
 727:    *
 728:    * @param   string  $color  a hex color
 729:    *
 730:    * @return  string          'light' or 'dark'
 731:    */
 732:   private function brightness( $color ) {
 733: 
 734:     if ( ! isset( $this->colors[ $color ][ 'brightness' ] ) ) {
 735:       $this->colors[ $color ][ 'brightness' ] = $this->getBrightness( $color );
 736:     }
 737:     return $this->colors[ $color ][ 'brightness' ];
 738: 
 739:   }
 740: 
 741: 
 742:   /**
 743:    * Retrieves the cached result of an altered color
 744:    *
 745:    * @since Taurus 1
 746:    *
 747:    * @param   string  $color  a hex color
 748:    *
 749:    * @return  mixed           the altered hex color if found, FALSE if not
 750:    */
 751:   private function cached( $color ) {
 752:     $cache = $this->cache . '/' . md5( $color );
 753:     $key = md5( $color );
 754: 
 755:     if ( file_exists( $cache ) ) {
 756:       return file_get_contents( $cache );
 757:     }
 758:     return FALSE;
 759: 
 760:   }
 761: 
 762: 
 763:   /**
 764:    * Caches an altered color in the color cache
 765:    *
 766:    * @since Taurus 1
 767:    *
 768:    * @param   string  $color  a hex color
 769:    *
 770:    */
 771:   private function cache( $color ) {
 772: 
 773:     file_put_contents( $this->cache . '/' . md5( $color ), $this->colors[$color]['altered'] );
 774: 
 775:   }
 776: 
 777: /*****************************************************************************
 778:  * END GETTER FUNCTIONS
 779:  ****************************************************************************/
 780: 
 781: /*****************************************************************************
 782:  * BEGIN CONVERSION FUNCTIONS
 783:  ****************************************************************************/
 784: 
 785:   /**
 786:    * Converts a Hex color to an RGB Color
 787:    *
 788:    * @see     color()
 789:    * @see     prepareicon()
 790:    * @see     checkhex()
 791:    * @see     validatehex()
 792:    * @see     normalizehex()
 793:    * @see     rgb()
 794:    * @see     hsv()
 795:    * @see     luminance()
 796:    * @see     brightness()
 797:    * @see     altered()
 798:    * @see     rgbtohex()
 799:    * @see     rgbtohsv()
 800:    * @see     hsvtorgb()
 801:    * @see     alter()
 802:    * @see     getluminance()
 803:    * @see     getBrightness()
 804:    *
 805:    * @since   Taurus 1
 806:    *
 807:    * @param   string  $color A hex color
 808:    * @return  array          An array of RGB values
 809:    */
 810:   public function hexToRgb( $hex ) {
 811: 
 812:     $r = hexdec( substr( $hex, 0, 2 ) );
 813:     $g = hexdec( substr( $hex, 2, 2 ) );
 814:     $b = hexdec( substr( $hex, 4, 2 ) );
 815:     return [ 'r' => $r, 'g' => $g, 'b' => $b ];
 816: 
 817:   }
 818: 
 819: 
 820:   /**
 821:    * Converts an RGB color to a Hex color
 822:    *
 823:    * @see     color()
 824:    * @see     prepareIcon()
 825:    * @see     checkHex()
 826:    * @see     validateHex()
 827:    * @see     normalizeHex()
 828:    * @see     rgb()
 829:    * @see     hsv()
 830:    * @see     luminance()
 831:    * @see     brightness()
 832:    * @see     altered()
 833:    * @see     hexToRgb()
 834:    * @see     rgbToHsv()
 835:    * @see     hsvToRgb()
 836:    * @see     alter()
 837:    * @see     getLuminance()
 838:    * @see     getBrightness()
 839:    *
 840:    * @since   Taurus 1
 841:    *
 842:    * @param   array  $rgb an associative array of RGB values
 843:    *
 844:    * @return  string      a hex color
 845:    */
 846:   public function rgbToHex( $rgb ) {
 847: 
 848:     $hex .= str_pad( dechex( $rgb[ 'r' ] ), 2, '0', STR_PAD_LEFT );
 849:     $hex .= str_pad( dechex( $rgb[ 'g' ] ), 2, '0', STR_PAD_LEFT );
 850:     $hex .= str_pad( dechex( $rgb[ 'b' ] ), 2, '0', STR_PAD_LEFT );
 851:     return $hex;
 852: 
 853:   }
 854: 
 855: 
 856:   /**
 857:    * Converts RGB color to HSV color
 858:    *
 859:    * @link [https://en.wikipedia.org/wiki/HSL_and_HSV] [color forumulas]
 860:    *
 861:    * @see     color()
 862:    * @see     prepareIcon()
 863:    * @see     checkHex()
 864:    * @see     validateHex()
 865:    * @see     normalizeHex()
 866:    * @see     rgb()
 867:    * @see     hsv()
 868:    * @see     luminance()
 869:    * @see     brightness()
 870:    * @see     altered()
 871:    * @see     hexToRgb()
 872:    * @see     rgbToHex()
 873:    * @see     hsvToRgb()
 874:    * @see     alter()
 875:    * @see     getLuminance()
 876:    * @see     getBrightness()
 877:    *
 878:    * @since   Taurus 1
 879:    *
 880:    * @param   array $rgb associative array of rgb values
 881:    *
 882:    * @return  array     an associate array of hsv values
 883:    */
 884:   public function rgbToHsv( $rgb ) {
 885: 
 886:     $r = $rgb[ 'r' ];
 887:     $g = $rgb[ 'g' ];
 888:     $b = $rgb[ 'b' ];
 889: 
 890: 
 891:     $min = min( $r, $g, $b );
 892:     $max = max( $r, $g, $b );
 893:     $chroma = $max - $min;
 894: 
 895:     //if $chroma is 0, then s is 0 by definition, and h is undefined but 0 by convention.
 896:     if ( $chroma == 0 ) {
 897:       return [ 'h' => 0, 's' => 0, 'v' => $max / 255 ];
 898:     }
 899: 
 900:     if ( $r == $max ) {
 901:       $h = ( $g - $b ) / $chroma;
 902: 
 903:       if ( $h < 0.0 )
 904:         $h += 6.0;
 905: 
 906:     } else if ( $g == $max ) {
 907:       $h = ( ( $b - $r ) / $chroma ) + 2.0;
 908:     } else {  //$b == $max
 909:       $h = ( ( $r - $g ) / $chroma ) + 4.0;
 910:     }
 911: 
 912:     $h *= 60.0;
 913:     $s = $chroma / $max;
 914:     $v = $max / 255;
 915: 
 916:     return [ 'h' => $h, 's' => $s, 'v' => $v ];
 917: 
 918:   }
 919: 
 920:   /**
 921:    * Convert HSV color to RGB
 922:    *
 923:    * @link    [https://en.wikipedia.org/wiki/HSL_and_HSV] [color forumulas]
 924:    *
 925:    * @see     color()
 926:    * @see     prepareIcon()
 927:    * @see     checkHex()
 928:    * @see     validateHex()
 929:    * @see     normalizeHex()
 930:    * @see     rgb()
 931:    * @see     hsv()
 932:    * @see     luminance()
 933:    * @see     brightness()
 934:    * @see     altered()
 935:    * @see     hexToRgb()
 936:    * @see     rgbToHex()
 937:    * @see     rgbToHsv()
 938:    * @see     alter()
 939:    * @see     getLuminance()
 940:    * @see     getBrightness()
 941:    *
 942:    * @since   Taurus 1
 943:    *
 944:    * @param   array $hsv associative array of hsv values ( 0 <= h < 360, 0 <= s <= 1, 0 <= v <= 1)
 945:    *
 946:    * @return  array  An array of RGB values
 947:    */
 948:   public function hsvToRgb( $hsv ) {
 949: 
 950:     $h = $hsv[ 'h' ];
 951:     $s = $hsv[ 's' ];
 952:     $v = $hsv[ 'v' ];
 953: 
 954:     $chroma = $s * $v;
 955:     $h /= 60.0;
 956:     $x = $chroma * ( 1.0 - abs( ( fmod( $h, 2.0 ) ) - 1.0 ) );
 957:     $min = $v - $chroma;
 958: 
 959:     if ( $h < 1.0 ) {
 960:       $r = $chroma;
 961:       $g = $x;
 962:     } else if ( $h < 2.0 ) {
 963:       $r = $x;
 964:       $g = $chroma;
 965:     } else if ( $h < 3.0 ) {
 966:       $g = $chroma;
 967:       $b = $x;
 968:     } else if ( $h < 4.0 ) {
 969:       $g = $x;
 970:       $b = $chroma;
 971:     } else if ( $h < 5.0 ) {
 972:       $r = $x;
 973:       $b = $chroma;
 974:     } else if ( $h <= 6.0 ) {
 975:       $r = $chroma;
 976:       $b = $x;
 977:     }
 978: 
 979:     $r = round( ( $r + $min ) * 255 );
 980:     $g = round( ( $g + $min ) * 255 );
 981:     $b = round( ( $b + $min ) * 255 );
 982: 
 983:     return [ 'r' => $r, 'g' => $g, 'b' => $b ];
 984: 
 985:   }
 986: 
 987: 
 988:   /**
 989:    * Gets the luminance of a color between 0 and 1
 990:    *
 991:    * @link    https://en.wikipedia.org/wiki/Luminance_(relative)
 992:    * @link    https://en.wikipedia.org/wiki/Luma_(video)
 993:    * @link    https://en.wikipedia.org/wiki/CCIR_601
 994:    *
 995:    * @see     color()
 996:    * @see     prepareIcon()
 997:    * @see     checkHex()
 998:    * @see     validateHex()
 999:    * @see     normalizeHex()
1000:    * @see     rgb()
1001:    * @see     hsv()
1002:    * @see     luminance()
1003:    * @see     brightness()
1004:    * @see     altered()
1005:    * @see     hexToRgb()
1006:    * @see     rgbToHex()
1007:    * @see     rgbToHsv()
1008:    * @see     hsvToRgb()
1009:    * @see     alter()
1010:    * @see     getBrightness()
1011:    *
1012:    * @since   Taurus 1
1013:    *
1014:    * @param   mixed  $color a hex color (string) or an associative array of RGB values
1015:    *
1016:    * @return  float         Luminance on a scale of 0 to 1
1017:    */
1018:   public function getLuminance( $color ) {
1019: 
1020:     if ( ! is_array( $color ) )
1021:       $rgb = $this->rgb( $color );
1022:     else
1023:       $rgb = $color;
1024: 
1025:     return ( 0.299 * $rgb[ 'r' ] + 0.587 * $rgb[ 'g' ] + 0.114 * $rgb[ 'b' ] ) / 255;
1026: 
1027:   }
1028: 
1029: 
1030:   /**
1031:    * Determines whether a color is 'light' or 'dark'
1032:    *
1033:    * @see     color()
1034:    * @see     prepareIcon()
1035:    * @see     checkHex()
1036:    * @see     validateHex()
1037:    * @see     normalizeHex()
1038:    * @see     rgb()
1039:    * @see     hsv()
1040:    * @see     luminance()
1041:    * @see     brightness()
1042:    * @see     altered()
1043:    * @see     hexToRgb()
1044:    * @see     rgbToHex()
1045:    * @see     rgbToHsv()
1046:    * @see     hsvToRgb()
1047:    * @see     alter()
1048:    * @see     getLuminance()
1049:    *
1050:    * @since   Taurus 1
1051:    *
1052:    * @param   string  $color  a hex color
1053:    *
1054:    * @return  string          either 'light' or 'dark'
1055:    */
1056:   public function getBrightness( $color ) {
1057: 
1058:     if ( isset( $this->colors[ $color ][ 'brightness' ] ) )
1059:       return $this->colors[ $color ][ 'brightness' ];
1060: 
1061:     if ( $this->luminance( $color ) > .5 )
1062:       $this->colors[ $color ][ 'brightness' ] = 'light';
1063:     else
1064:       $this->colors[ $color ][ 'brightness' ] = 'dark';
1065: 
1066:     return $this->colors[ $color ][ 'brightness' ];
1067: 
1068:   }
1069: 
1070: 
1071:   /**
1072:    * Either lightens or darkens an image
1073:    *
1074:    * The function starts with a hex color and converts it into
1075:    * an RGB color space and then to an HSV color space. The V(alue)
1076:    * in HSV is set between 0 (black) and 1 (white), which is a
1077:    * measure of 'brightness' where 0.5 is neutral. Thus, we retain
1078:    * the hue and saturation and keep the relative brightness of the
1079:    * color by pushing it on the other side of neutral but at the
1080:    * same distance from neutral. E.g.: 0.7 becomes 0.3; 0.12 becomes
1081:    * 0.88; 0.0 becomes 1.0; and 0.5 becomes 0.5.
1082:    *
1083:    * @see     color()
1084:    * @see     prepareIcon()
1085:    * @see     checkHex()
1086:    * @see     validateHex()
1087:    * @see     normalizeHex()
1088:    * @see     rgb()
1089:    * @see     hsv()
1090:    * @see     luminance()
1091:    * @see     brightness()
1092:    * @see     altered()
1093:    * @see     hexToRgb()
1094:    * @see     rgbToHex()
1095:    * @see     rgbToHsv()
1096:    * @see     hsvToRgb()
1097:    * @see     getLuminance()
1098:    * @see     getBrightness()
1099:    *
1100:    * @since   Taurus 1
1101:    *
1102:    * @param   string  $color  a hex color
1103:    *
1104:    * @return  string          a hex color
1105:    */
1106:   public function alter( $color ) {
1107: 
1108:     $hsv = $this->hsv( $color );
1109:     $hsv[ 'v' ] = 1 - $hsv[ 'v' ];
1110:     $rgb = $this->hsvToRgb( $hsv );
1111:     $this->colors[ $color ][ 'altered' ] = $this->rgbToHex( $rgb );
1112:     $altered = $this->color( $this->colors[ $color ][ 'altered' ] );
1113: 
1114:     $this->cache( $color ); // Cache the conversion
1115: 
1116:     return $this->colors[ $color ][ 'altered' ];
1117: 
1118:   }
1119: 
1120:  /*****************************************************************************
1121:  * END CONVERSION FUNCTIONS
1122:  ****************************************************************************/
1123: 
1124:  /*****************************************************************************
1125:  * BEGIN VALIDATION / NORMALIZATION FUNCTIONS
1126:  ****************************************************************************/
1127: 
1128:   /**
1129:    * Checks to see if a color is a valid hex and normalizes the hex color
1130:    *
1131:    * @see     color()
1132:    * @see     prepareIcon()
1133:    * @see     validateHex()
1134:    * @see     normalizeHex()
1135:    * @see     rgb()
1136:    * @see     hsv()
1137:    * @see     luminance()
1138:    * @see     brightness()
1139:    * @see     altered()
1140:    * @see     hexToRgb()
1141:    * @see     rgbToHex()
1142:    * @see     rgbToHsv()
1143:    * @see     hsvToRgb()
1144:    * @see     alter()
1145:    * @see     getLuminance()
1146:    * @see     getBrightness()
1147:    *
1148:    * @since   Taurus 1
1149:    *
1150:    * @param   string  $color A hex color
1151:    *
1152:    * @return  mixed       FALSE on non-hex or hex color (normalized) to six characters and lowercased
1153:    */
1154:   public function checkHex( $hex ) {
1155: 
1156:     return $this->validateHex( $this->normalizeHex( $hex ) );
1157: 
1158:   }
1159: 
1160: 
1161:   /**
1162:    * Normalizes all hex colors to six, lowercase characters
1163:    *
1164:    * @see     color()
1165:    * @see     prepareIcon()
1166:    * @see     checkHex()
1167:    * @see     validateHex()
1168:    * @see     rgb()
1169:    * @see     hsv()
1170:    * @see     luminance()
1171:    * @see     brightness()
1172:    * @see     altered()
1173:    * @see     hexToRgb()
1174:    * @see     rgbToHex()
1175:    * @see     rgbToHsv()
1176:    * @see     hsvToRgb()
1177:    * @see     alter()
1178:    * @see     getLuminance()
1179:    * @see     getBrightness()
1180:    *
1181:    * @since   Taurus 1
1182:    *
1183:    * @param   string  $hex a hex color
1184:    *
1185:    * @return  string      a normalized hex color
1186:    */
1187:   public function normalizeHex( $hex ) {
1188: 
1189:     $hex = strtolower( str_replace( '#', '', $hex ) );
1190:     if ( strlen( $hex ) == 3 )
1191:       $hex = preg_replace( "/(.)(.)(.)/", "\\1\\1\\2\\2\\3\\3", $hex );
1192:     return $hex;
1193: 
1194:   }
1195: 
1196:   /**
1197:    * Validates a hex color
1198:    *
1199:    * @see     color()
1200:    * @see     prepareIcon()
1201:    * @see     checkHex()
1202:    * @see     normalizeHex()
1203:    * @see     rgb()
1204:    * @see     hsv()
1205:    * @see     luminance()
1206:    * @see     brightness()
1207:    * @see     altered()
1208:    * @see     hexToRgb()
1209:    * @see     rgbToHex()
1210:    * @see     rgbToHsv()
1211:    * @see     hsvToRgb()
1212:    * @see     alter()
1213:    * @see     getLuminance()
1214:    * @see     getBrightness()
1215:    *
1216:    * @since   Taurus 1
1217:    *
1218:    * @param   string  $hex a hex color
1219:    *
1220:    * @return  mixed   FALSE on failure, the hex value on success
1221:    */
1222:   public function validateHex( $hex ) {
1223: 
1224:     if ( strlen( $hex ) != 3 && strlen( $hex ) != 6 )
1225:       return FALSE; // Not a valid hex value
1226:     if ( ! preg_match( "/([0-9a-f]{3}|[0-9a-f]{6})/", $hex ) )
1227:       return FALSE; // Not a valid hex value
1228:     return $hex;
1229: 
1230:   }
1231: 
1232: 
1233: /*****************************************************************************
1234:  * END VALIDATION / NORMALIZATION FUNCTIONS
1235:  ****************************************************************************/
1236: /*****************************************************************************
1237:  * END COLOR FUNCTIONS
1238:  ****************************************************************************/
1239: 
1240: }
1241: 
1242: endif;
1243: 
1244: 
Alfred Bundler API documentation generated by ApiGen 2.8.0