├── .codeclimate.yml ├── .editorconfig ├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── LICENSE ├── README.md ├── autoload.php ├── composer.json ├── composer.lock ├── meta └── sample.php ├── php5 ├── cache.php ├── check.php ├── color.php ├── convert.php ├── css.php ├── error.php ├── generate.php ├── hsl.php ├── main.php ├── main_peripheral.php ├── modify.php ├── regulate.php ├── scheme.php └── yiq_scheme.php ├── phpunit-scrutinizer.xml ├── phpunit-travis.xml ├── phpunit.xml ├── src ├── check.php ├── convert │ ├── cmyk.php │ ├── hex.php │ ├── hsb.php │ ├── hsl.php │ └── rgb.php ├── css.php ├── data │ ├── cache.php │ ├── color │ │ ├── space.php │ │ ├── space │ │ │ ├── cmyk.php │ │ │ ├── hsb.php │ │ │ ├── hsl.php │ │ │ └── rgb.php │ │ ├── type.php │ │ └── x11.php │ ├── store.old.php │ ├── store.php │ └── type.php ├── error.php ├── exceptions │ ├── general_error.php │ ├── invalid_argument.php │ ├── invalid_color.php │ ├── invalid_config.php │ ├── invalid_value.php │ └── value_out_of_range.php ├── generate.php ├── hsl.php ├── interfaces │ └── converter.php ├── main.php ├── main_peripheral.php ├── modify.php ├── regulate.php ├── scheme.php ├── traits │ └── converter.php ├── validate.php └── yiq_scheme.php ├── tasks.todo ├── testing ├── bootstrap.php └── tests │ ├── 00_ErrorTest.php │ ├── 01_RegulateTest.php │ ├── 02_ConverterTest.php │ ├── 03_GeneratorTest.php │ ├── 04_CheckTest.php │ ├── 05_SchemeTest.php │ ├── 06_YIQSchemeTest.php │ ├── 07_CacheTest.php │ ├── 08_HSLTest.php │ ├── 09_ColorTest.php │ ├── 10_MainTest.php │ ├── 11_CSSTest.php │ └── 12_CloneTest.php └── tput.exe.stackdump /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | duplication: 3 | enabled: true 4 | config: 5 | languages: 6 | - php 7 | fixme: 8 | enabled: true 9 | phan: 10 | enabled: true 11 | config: 12 | file_extensions: "php" 13 | fixme: 14 | enabled: true 15 | markdownlint: 16 | enabled: true 17 | ratings: 18 | paths: 19 | - "**.php" 20 | - "**.md" 21 | exclude_paths: 22 | - "meta/" 23 | - "testing/" 24 | - "php5/" 25 | - "autload.php" 26 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Standard 2 | [*] 3 | charset = utf-8 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_size = 2 7 | indent_style = tab 8 | 9 | # Spaces are important 10 | [*.yml] 11 | indent_style = space 12 | 13 | [*.sql] 14 | indent_style = space 15 | 16 | # Windows endings 17 | [*.bat] 18 | end_of_line = crlf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Unit Testing ### 2 | /coverage 3 | /vendor 4 | /meta/test.php 5 | sample.html 6 | 7 | ### OS ### 8 | .DS_Store 9 | .DS_Store? 10 | ._* 11 | .Spotlight-V100 12 | .Trashes 13 | Icon? 14 | ehthumbs.db 15 | Thumbs.db 16 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | build: 2 | tests: 3 | override: 4 | - 5 | command: 'phpunit -c phpunit-scrutinizer.xml' 6 | environment: 7 | php: 8 | version: 7.0.8 9 | tools: 10 | external_code_coverage: 11 | timeout: 600 12 | filter: 13 | paths: [src/*] 14 | checks: 15 | php: 16 | verify_property_names: true 17 | verify_argument_usable_as_reference: true 18 | verify_access_scope_valid: true 19 | variable_existence: true 20 | use_self_instead_of_fqcn: true 21 | use_statement_alias_conflict: true 22 | uppercase_constants: true 23 | uppercase_basic_constants: true 24 | unused_variables: true 25 | unused_properties: true 26 | unused_parameters: true 27 | unused_methods: true 28 | unreachable_code: true 29 | too_many_arguments: true 30 | spacing_of_function_arguments: true 31 | spacing_around_non_conditional_operators: true 32 | spacing_around_conditional_operators: true 33 | space_after_cast: true 34 | single_namespace_per_use: true 35 | security_vulnerabilities: true 36 | return_doc_comments: true 37 | return_doc_comment_if_not_inferrable: true 38 | require_scope_for_properties: true 39 | require_scope_for_methods: true 40 | require_php_tag_first: true 41 | require_braces_around_control_structures: true 42 | remove_trailing_whitespace: true 43 | remove_php_closing_tag: true 44 | property_assignments: true 45 | prefer_while_loop_over_for_loop: true 46 | prefer_unix_line_ending: true 47 | precedence_mistakes: true 48 | precedence_in_conditions: true 49 | php5_style_constructor: true 50 | parameter_non_unique: true 51 | parameter_doc_comments: true 52 | param_doc_comment_if_not_inferrable: true 53 | overriding_private_members: true 54 | optional_parameters_at_the_end: true 55 | non_commented_empty_catch_block: true 56 | no_trailing_whitespace: true 57 | no_space_inside_cast_operator: true 58 | no_space_between_concatenation_operator: true 59 | no_space_before_semicolon: true 60 | no_space_around_object_operator: true 61 | no_short_open_tag: true 62 | no_non_implemented_abstract_methods: true 63 | no_goto: true 64 | no_eval: true 65 | no_empty_statements: true 66 | no_else_if_statements: true 67 | no_debug_code: true 68 | missing_arguments: true 69 | method_calls_on_non_object: true 70 | lowercase_php_keywords: true 71 | instanceof_class_exists: true 72 | function_body_start_on_same_line: true 73 | foreach_usable_as_reference: true 74 | foreach_traversable: true 75 | fix_use_statements: 76 | remove_unused: true 77 | preserve_multiple: false 78 | preserve_blanklines: false 79 | order_alphabetically: true 80 | fix_php_opening_tag: true 81 | fix_doc_comments: true 82 | ensure_lower_case_builtin_functions: true 83 | encourage_single_quotes: true 84 | encourage_postdec_operator: true 85 | deprecated_code_usage: true 86 | deadlock_detection_in_loops: true 87 | code_rating: true 88 | closure_use_not_conflicting: true 89 | catch_class_exists: true 90 | avoid_usage_of_logical_operators: true 91 | avoid_unnecessary_concatenation: true 92 | avoid_todo_comments: true 93 | avoid_space_indentation: true 94 | avoid_multiple_statements_on_same_line: true 95 | avoid_fixme_comments: true 96 | avoid_corrupting_byteorder_marks: true 97 | assignment_of_null_return: true 98 | argument_type_checks: true 99 | align_assignments: true 100 | newline_at_end_of_file: true 101 | more_specific_types_in_doc_comments: true 102 | avoid_perl_style_comments: true 103 | 104 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | before_script: 3 | - wget https://scrutinizer-ci.com/ocular.phar 4 | - composer install -n 5 | script: 6 | - ./vendor/phpunit/phpunit/phpunit -c phpunit-travis.xml 7 | after_script: 8 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 9 | - php vendor/bin/codacycoverage clover coverage.clover 10 | - ./vendor/bin/test-reporter --coverage-report coverage.clover 11 | php: 12 | - 5.6 13 | - 7.0 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The PHP-Color documentation & source code (hereafter referred to as "Library") by Nicholas Summers (hereafter referred to as "Author") is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License with the below "Additional Terms" superseding it. To view a copy of the Creative Commons license, visit https://creativecommons.org/licenses/by-nc-nd/4.0/. From now on "License" refers to this combination of licensing. 2 | 3 | Additional Terms: 4 | 5 | 1. Any person or non-profit entity or may use this Library for personal or professional use as long as the Library as well as any of its parts are not sold in any fashion, and users are not forced to pay to use it in any way. 6 | 2. Anyone may use this Library for purely internal use as long as the Library as well as any of its parts are available without payment and are not publicly accessible. 7 | 3. Anyone seeking to sell this Library or use this Library in a commercial environment MUST first obtain a OEM license from the Author. 8 | 4. Anyone in direct violation of this License is liable for a minimum of $50,000 in damages, plus an additional $10 per user, and agrees to refund any charge or fees collected as a result of violating this License. 9 | 5. By downloading or using this Library you agree to all the License terms. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Color   [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://njordon.mit-license.org/@2016) [![Travis Build Status](https://img.shields.io/travis/ProjectCleverWeb/PHP-Color.svg?maxAge=2592000&style=flat-square)](https://travis-ci.org/ProjectCleverWeb/PHP-Color) [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/ProjectCleverWeb/PHP-Color.svg?maxAge=2592000&style=flat-square)](https://scrutinizer-ci.com/g/ProjectCleverWeb/PHP-Color/) [![Scrutinizer Code Coverage](https://img.shields.io/scrutinizer/coverage/g/ProjectCleverWeb/PHP-Color.svg?maxAge=2592000&style=flat-square)](https://scrutinizer-ci.com/g/ProjectCleverWeb/PHP-Color/) [![Code Climate Code GPA](https://img.shields.io/codeclimate/github/kabisaict/flow.svg?maxAge=2592000&style=flat-square)](https://codeclimate.com/github/ProjectCleverWeb/PHP-Color) 2 | 3 | This is a PHP 7 library for working with RGB, HSL, and Hexadecimal colors. Create schemes, modify specific color properties, export CMYK, and make color suggestions quickly and easily with this stand-alone library. 4 | 5 | Demo: [jsfiddle.net/t3LL4q14](http://jsfiddle.net/t3LL4q14/embedded/result/) 6 | 7 | ### Download: 8 | 9 | [![GitHub release](https://img.shields.io/github/release/ProjectCleverWeb/PHP-Color.svg?maxAge=2592000&style=flat-square)](https://github.com/ProjectCleverWeb/PHP-Color/releases) 10 | 11 | Copyright © 2016 Nicholas Jordon — All Rights Reserved 12 | 13 | ## Features 14 | 15 | * Convert any color between the RGB, HSL, HSB, Hexadecimal, and CMYK color spectrums. 16 | * Dynamically generate 10 different color scheme algorithims for any color. (That's over 165,000,000 possible schemes) 17 | * Check whether a color appears visually dark or light. (uses [YIQ](https://en.wikipedia.org/wiki/YIQ) weights for better accuraccy) 18 | * Easily modify a color's hue, saturation, light, red, green, blue, and alpha (transparcency) values. 19 | * Generate CSS values on the fly 20 | * Find the contrast between 2 colors. 21 | * Dynamically generate random colors, including for specific color ranges. 22 | * All errors are recoverable, and errors can be triggered as exceptions (default), using `trigger_error()`, or can be turned off for all instances. 23 | 24 | ## Installation & Usage 25 | 26 | See the [Official Wiki on Github](https://github.com/ProjectCleverWeb/PHP-Color/wiki) for all documentation. 27 | 28 | ## Contributing 29 | 30 | **Contributing *via* Suggestions:**
31 | The best way to submit a suggestion is to open an issue on Github and prefix the 32 | title with `[Suggestion]`. Alternatively, you can email your suggestions to 33 | projectcleverweb(at)gmail(dot)com. 34 | 35 | **Contributing *via* Reporting Problems:**
36 | All problems must be reported via Github's 37 | [issue tracker](https://github.com/ProjectCleverWeb/PHP-Color/issues). 38 | 39 | **Contributing *via* Code:** 40 | 41 | 1. Fork the repo on Github: [github.com/ProjectCleverWeb/PHP-Color](https://github.com/ProjectCleverWeb/PHP-Color) 42 | 2. Make your changes. 43 | 3. Send a pull request to have your changes reviewed. 44 | 45 | ## License 46 | 47 | The PHP-Color documentation & source code (hereafter referred to as "Library") by Nicholas Summers (hereafter referred to as "Author") is licensed 48 | under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License with the below "Additional Terms" superseding it. 49 | To view a copy of the Creative Commons license, visit [creativecommons.org/licenses/by-nc-nd/4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/). From now on "License" refers to this combination of licensing. 50 | 51 | **Additional Terms:** 52 | 53 | 1. Any person or non-profit entity or may use this Library for personal or professional use as long as the Library as well as any of its parts are not sold in any fashion, and users are not forced to pay to use it in any way. 54 | 2. Anyone may use this Library for purely internal use as long as the Library as well as any of its parts are available without payment and are not publicly accessible. 55 | 3. Anyone seeking to sell this Library or use this Library in a commercial environment MUST first obtain a OEM license from the Author. 56 | 4. Anyone in direct violation of this License is liable for a minimum of $50,000 in damages, plus an additional $10 per user, and agrees to refund any charge or fees collected as a result of violating this License. 57 | 5. By downloading or using this Library you agree to all the License terms. 58 | -------------------------------------------------------------------------------- /autoload.php: -------------------------------------------------------------------------------- 1 | =5.3" 52 | }, 53 | "require-dev": { 54 | "phpunit/phpunit": "~5.5.5", 55 | "codeclimate/php-test-reporter": "dev-master", 56 | "codacy/coverage": "dev-master" 57 | }, 58 | "autoload": { 59 | "files": ["autoload.php"] 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /meta/sample.php: -------------------------------------------------------------------------------- 1 | 72, 's' => 20, 'l' => 20)), 22 | new main(array('h' => 108, 's' => 30, 'l' => 30)), 23 | new main(array('h' => 144, 's' => 40, 'l' => 40)), 24 | new main(array('h' => 180, 's' => 50, 'l' => 50)), 25 | new main(array('h' => 216, 's' => 60, 'l' => 60)), 26 | new main(array('h' => 252, 's' => 70, 'l' => 70)), 27 | new main(array('h' => 288, 's' => 80, 'l' => 80)), 28 | new main(array('h' => 324, 's' => 90, 'l' => 90)) 29 | ]; 30 | 31 | 32 | $colors = array_reverse($colors); 33 | 34 | // Scheme functions and their definitions 35 | $funcs = [ 36 | 'shades' => '5 different shades of one color. (unaffected by YIQ)', 37 | 'monochromatic' => '5 complementary shades of one color. (unaffected by YIQ)', 38 | 'analogous' => 'These colors are all close to each other on a color wheel.', 39 | 'complementary' => '2 of these colors are a different shade of the base color. The other 2 are a weighted opposite of the base color.', 40 | 'triad' => 'These colors are all equally distanced from each other on a color wheel, 2 of which have an alternate shade.', 41 | 'weighted_triad' => 'These colors are all similarly distanced from each other on a color wheel, 2 of which have an alternate shade. These colors are all slightly closer to the base color than in a normal triad.', 42 | 'tetrad' => '3 of these colors are all equally distanced from each other on a color wheel, plus 1 alternated shade for the base color and the 1 color that is opposite of the base color.', 43 | 'weighted_tetrad' => '3 of these colors are all similarly distanced from each other on a color wheel, the base color has an alternate shade, and there is a weighted opposite color. These colors are all slightly closer to the base color than in a normal tetrad.', 44 | 'compound' => 'These colors use mathematical offsets that usually complement each other well, and can highlight the base color.', 45 | 'rectangular' => '4 of these colors form a rectangle on a color wheel, and 1 color is an alternate shade for the base color.' 46 | ]; 47 | $fmt = 48 | '
49 |
50 | #%4$s 51 | #%6$s 52 | #%2$s 53 | #%8$s 54 | #%10$s 55 |
56 |
57 |
'.PHP_EOL; 58 | $output = '
'; 59 | $output .= '

Scheme Descriptions

'; 60 | foreach ($funcs as $name => $desc) { 61 | $output .= '
'; 62 | $output .= sprintf( 63 | '
%s
%s
', 64 | ucwords(str_replace('_', ' ', $name)), 65 | $desc 66 | ); 67 | $output .= '
'; 68 | } 69 | $output .= '
YIQ vs Standard Schemes
Standard schemes use equally sized color spaces for red, green, and blue. However, the human eye can\'t see blue as well as it can see red, and it also can\'t see red as well as it can see green. To account for this, schemes can optionally use the YIQ spectrum (which accounts for these differences in the human eye) in their calculations rather than the standard RGB spectrum.
'; 70 | foreach ($colors as $i => $color) { 71 | $rgb = $color->rgb(); 72 | $hex = $color->hex(); 73 | $hex_text = $color->is_dark() ? 'FFFFFF' : '000000'; 74 | $hsl = $color->hsl(); 75 | $hsb = $color->hsb(); 76 | $cmyk = $color->cmyk(); 77 | $background = sprintf(' style="background: #%s"', $color->is_dark() ? 'FFFFFF' : '282828'); 78 | $header_bg = $color->is_dark() ? '' : ' inverted'; 79 | $output .= sprintf( 80 | '
81 |

82 | #%1$s 83 |
rgb(%3$s) / hsl(%4$s) / hsb(%5$s) / cmyk(%6$s)
84 |

85 |
', 86 | $hex, 87 | $hex_text, 88 | implode(',', array_slice($rgb, 0, 3)), 89 | implode(',', array_slice($hsl, 0, 3)), 90 | implode(',', array_slice($hsb, 0, 3)), 91 | implode(',', array_slice($cmyk, 0, 4)) 92 | ); 93 | foreach ($funcs as $func => $desc) { 94 | $output .= '
'; 95 | 96 | $scheme = $color->scheme($func, 'hsl'); 97 | $yiq_scheme = $color->yiq_scheme($func, 'hsl'); 98 | $schemes = array(); 99 | foreach ($scheme as $key => $color_scheme) { 100 | $color_scheme = new main($color_scheme); 101 | $yiq_color_scheme = new main($yiq_scheme[$key]); 102 | $schemes['std'][$key] = array( 103 | 'rgb' => $color_scheme->rgb(), 104 | 'hex' => $color_scheme->hex(), 105 | 'text' => $color_scheme->is_dark() ? 'FFFFFF' : '000000' 106 | ); 107 | $schemes['yiq'][$key] = array( 108 | 'rgb' => $yiq_color_scheme->rgb(), 109 | 'hex' => $yiq_color_scheme->hex(), 110 | 'text' => $yiq_color_scheme->is_dark() ? 'FFFFFF' : '000000' 111 | ); 112 | unset($color_scheme, $yiq_color_scheme); 113 | } 114 | 115 | $adobe = sprintf( 116 | 'https://color.adobe.com/create/color-wheel/?base=2&rule=Custom&selected=2&name=%s&mode=hsv&rgbvalues=%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s&swatchOrder=0,1,2,3,4', 117 | urlencode(sprintf('Hex %s - %s', $hex, ucwords(str_replace('_', ' ', $func)))), 118 | $schemes['std'][1]['rgb']['r'] / 255, 119 | $schemes['std'][1]['rgb']['g'] / 255, 120 | $schemes['std'][1]['rgb']['b'] / 255, 121 | $schemes['std'][2]['rgb']['r'] / 255, 122 | $schemes['std'][2]['rgb']['g'] / 255, 123 | $schemes['std'][2]['rgb']['b'] / 255, 124 | $schemes['std'][0]['rgb']['r'] / 255, 125 | $schemes['std'][0]['rgb']['g'] / 255, 126 | $schemes['std'][0]['rgb']['b'] / 255, 127 | $schemes['std'][3]['rgb']['r'] / 255, 128 | $schemes['std'][3]['rgb']['g'] / 255, 129 | $schemes['std'][3]['rgb']['b'] / 255, 130 | $schemes['std'][4]['rgb']['r'] / 255, 131 | $schemes['std'][4]['rgb']['g'] / 255, 132 | $schemes['std'][4]['rgb']['b'] / 255 133 | ); 134 | $yiq_adobe = sprintf( 135 | 'https://color.adobe.com/create/color-wheel/?base=2&rule=Custom&selected=2&name=%s&mode=hsv&rgbvalues=%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s&swatchOrder=0,1,2,3,4', 136 | urlencode(sprintf('Hex %s - %s', $hex, 'YIQ '.ucwords(str_replace('_', ' ', $func)))), 137 | $schemes['yiq'][1]['rgb']['r'] / 255, 138 | $schemes['yiq'][1]['rgb']['g'] / 255, 139 | $schemes['yiq'][1]['rgb']['b'] / 255, 140 | $schemes['yiq'][2]['rgb']['r'] / 255, 141 | $schemes['yiq'][2]['rgb']['g'] / 255, 142 | $schemes['yiq'][2]['rgb']['b'] / 255, 143 | $schemes['yiq'][0]['rgb']['r'] / 255, 144 | $schemes['yiq'][0]['rgb']['g'] / 255, 145 | $schemes['yiq'][0]['rgb']['b'] / 255, 146 | $schemes['yiq'][3]['rgb']['r'] / 255, 147 | $schemes['yiq'][3]['rgb']['g'] / 255, 148 | $schemes['yiq'][3]['rgb']['b'] / 255, 149 | $schemes['yiq'][4]['rgb']['r'] / 255, 150 | $schemes['yiq'][4]['rgb']['g'] / 255, 151 | $schemes['yiq'][4]['rgb']['b'] / 255 152 | ); 153 | 154 | $output .= sprintf( 155 | '

%s

', 156 | ucwords(str_replace('_', ' ', $func)), 157 | $adobe, 158 | $yiq_adobe 159 | ); 160 | $output .= sprintf( 161 | $fmt, 162 | $i, // %1$s 163 | $schemes['std'][0]['hex'], // %2$s 164 | $schemes['std'][0]['text'], // %3$s 165 | $schemes['std'][1]['hex'], // %4$s 166 | $schemes['std'][1]['text'], // %5$s 167 | $schemes['std'][2]['hex'], // %6$s 168 | $schemes['std'][2]['text'], // %7$s 169 | $schemes['std'][3]['hex'], // %8$s 170 | $schemes['std'][3]['text'], // %9$s 171 | $schemes['std'][4]['hex'], // %10$s 172 | $schemes['std'][4]['text'] // %11$s 173 | ); 174 | if (!in_array($func, array('shades', 'monochromatic'))) { 175 | $output .= '

YIQ:

'.PHP_EOL; 176 | $output .= sprintf( 177 | $fmt, 178 | $i, // %1$s 179 | $schemes['yiq'][0]['hex'], // %2$s 180 | $schemes['yiq'][0]['text'], // %3$s 181 | $schemes['yiq'][1]['hex'], // %4$s 182 | $schemes['yiq'][1]['text'], // %5$s 183 | $schemes['yiq'][2]['hex'], // %6$s 184 | $schemes['yiq'][2]['text'], // %7$s 185 | $schemes['yiq'][3]['hex'], // %8$s 186 | $schemes['yiq'][3]['text'], // %9$s 187 | $schemes['yiq'][4]['hex'], // %10$s 188 | $schemes['yiq'][4]['text'] // %11$s 189 | ); 190 | } else { 191 | $output .= '
YIQ Can\'t Affect This Scheme.
'.PHP_EOL; 192 | } 193 | $output .= '
'; 194 | } 195 | } 196 | $output .= '
'; 197 | 198 | file_put_contents(__DIR__.'/sample.html', $output); 199 | -------------------------------------------------------------------------------- /php5/cache.php: -------------------------------------------------------------------------------- 1 | reset(); 30 | $this->active = TRUE; 31 | } 32 | 33 | /** 34 | * Reset the entire cache 35 | * 36 | * @return void 37 | */ 38 | public function reset() { 39 | $this->data = array(); 40 | } 41 | 42 | /** 43 | * Store a value in the cache 44 | * 45 | * @param string $func The function trying to store data (should be __FUNCTION__) 46 | * @param string $id The storage ID 47 | * @param mixed $value The value to store 48 | */ 49 | public function set($func, $id, $value) { 50 | if ($this->active) { 51 | $this->data[$func] = array($id => $value); 52 | } 53 | } 54 | 55 | /** 56 | * Get a value from the cache 57 | * 58 | * @param string $func The function trying to get data (should be __FUNCTION__) 59 | * @param string $id The storage ID 60 | * @return mixed The value stored or NULL 61 | */ 62 | public function get($func, $id) { 63 | if ($this->active && isset($this->data[$func][$id])) { 64 | return $this->data[$func][$id]; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /php5/check.php: -------------------------------------------------------------------------------- 1 | = $check_score returns FALSE, otherwise TRUE 22 | */ 23 | public static function is_dark($r = 0, $g = 0, $b = 0, $check_score = 128) { 24 | if (generate::yiq_score($r, $g, $b) >= $check_score) { 25 | return FALSE; 26 | } 27 | return TRUE; 28 | } 29 | 30 | /** 31 | * Measures the visual contrast of 2 RGB colors. 32 | * 33 | * NOTE: most colors do not have a 100% contrasting opposite, but all colors 34 | * do have a contrasting opposite that is at least 50%. 35 | * 36 | * @param array $rgb1 The first color, array where offsets 'r', 'g', & 'b' contain their respective values. 37 | * @param array $rgb2 The second color, array where offsets 'r', 'g', & 'b' contain their respective values. 38 | * @return float The visual contrast as a percentage (e.g. 12.345) 39 | */ 40 | public static function rgb_contrast($rgb1, $rgb2) { 41 | $r = (max($rgb1['r'], $rgb2['r']) - min($rgb1['r'], $rgb2['r'])) * 299; 42 | $g = (max($rgb1['g'], $rgb2['g']) - min($rgb1['g'], $rgb2['g'])) * 587; 43 | $b = (max($rgb1['b'], $rgb2['b']) - min($rgb1['b'], $rgb2['b'])) * 114; 44 | // Sum => Average => Convert to percentage 45 | return ($r + $g + $b) / 1000 / 2.55; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /php5/color.php: -------------------------------------------------------------------------------- 1 | hsl; 63 | return $temp(); 64 | } 65 | 66 | /** 67 | * Serializes this object. 68 | * 69 | * @return string The serialized object 70 | */ 71 | public function serialize() { 72 | return json_encode($this->rgb + array('a' => $this->alpha)); 73 | } 74 | 75 | /** 76 | * Unserializes this object. 77 | * 78 | * @param string $serialized The object as a serialized string 79 | * @return void 80 | */ 81 | public function unserialize($serialized) { 82 | $unserialized = (array) json_decode((string) $serialized); 83 | regulate::rgb_array($unserialized); 84 | $this->import_rgb($unserialized); 85 | } 86 | 87 | /** 88 | * Serializes this object into JSON. 89 | * 90 | * @return string The serialized object 91 | */ 92 | public function jsonSerialize() { 93 | return $this->rgb + array('a' => $this->alpha); 94 | } 95 | 96 | /** 97 | * Determine the type of color being used. 98 | * 99 | * @param mized $color The color in question 100 | * @return string The color type as a string, returns 'error' if $color is invalid 101 | */ 102 | public static function get_type($color) { 103 | if (is_array($color)) { 104 | return static::_get_array_type($color); 105 | } elseif (is_string($color)) { 106 | return 'hex'; 107 | } elseif (is_int($color)) { 108 | return 'int'; 109 | } 110 | return 'error'; 111 | } 112 | 113 | /** 114 | * Determine the type of color being used if it is an array. 115 | * 116 | * @param array $color The color in question 117 | * @return string The color type as a string, returns 'error' if $color is invalid 118 | */ 119 | protected static function _get_array_type($color) { 120 | $color = array_change_key_case($color); 121 | unset($color['a']); // ignore alpha channel 122 | ksort($color); 123 | $type = implode('', array_keys($color)); 124 | $types = array( 125 | 'bgr' => 'rgb', 126 | 'hls' => 'hsl', 127 | 'bhs' => 'hsb', 128 | 'ckmy' => 'cmyk' 129 | ); 130 | if (isset($types[$type])) { 131 | return $types[$type]; 132 | } 133 | return 'error'; 134 | } 135 | 136 | /** 137 | * Get (and set) the alpha channel 138 | * 139 | * @param mixed $new_alpha If numeric, the alpha channel is set to this value 140 | * @return float The current alpha value 141 | */ 142 | public function alpha($new_alpha = NULL) { 143 | if (is_numeric($new_alpha)) { 144 | $this->alpha = (float) $new_alpha; 145 | } 146 | return $this->alpha; 147 | } 148 | 149 | /** 150 | * Handles general errors when importing, and forces the input to be valid. 151 | * 152 | * @return void 153 | */ 154 | protected function import_error() { 155 | error::call(sprintf( 156 | 'The color supplied to %s\'s constructor was not valid', 157 | __CLASS__ 158 | )); 159 | $this->import_rgb(array(0, 0, 0)); 160 | } 161 | 162 | /** 163 | * Import the alpha channel from a color array, or create one if it doesn't exist 164 | * 165 | * @param array $color The color array to check 166 | * @return void 167 | */ 168 | protected function import_alpha($color) { 169 | if (isset($color['a'])) { 170 | $this->alpha = (float) $color['a']; 171 | } else { 172 | $this->alpha = 100.0; 173 | } 174 | } 175 | 176 | /** 177 | * Handles importing of another instance of color 178 | * 179 | * @return void 180 | */ 181 | protected function import_color($color) { 182 | $this->rgb = $color->rgb; 183 | $this->hex = $color->hex; 184 | $this->hsl = clone $color->hsl; 185 | $this->alpha = $color->alpha; 186 | } 187 | 188 | /** 189 | * Imports a RGB array. 190 | * 191 | * @param array $color Array with offsets 'r', 'g', 'b' 192 | * @return void 193 | */ 194 | public function import_rgb($color) { 195 | regulate::rgb_array($color); 196 | $this->rgb = array_intersect_key($color, array('r' => 0, 'g' => 0, 'b' => 0)); 197 | $this->hex = convert::rgb_to_hex($this->rgb['r'], $this->rgb['g'], $this->rgb['b']); 198 | $this->hsl = new hsl($this->rgb); 199 | $this->import_alpha($color); 200 | } 201 | 202 | /** 203 | * Imports a hsl array. 204 | * 205 | * @param array $color Array with offsets 'h', 's', 'l' 206 | * @return void 207 | */ 208 | public function import_hsl($color) { 209 | regulate::hsl_array($color); 210 | $this->rgb = convert::hsl_to_rgb($color['h'], $color['s'], $color['l']); 211 | $this->hsl = new hsl($this->rgb); 212 | $this->hex = convert::rgb_to_hex($this->rgb['r'], $this->rgb['g'], $this->rgb['b']); 213 | $this->import_alpha($color); 214 | } 215 | 216 | /** 217 | * Imports a hsb array. 218 | * 219 | * @param array $color Array with offsets 'h', 's', 'b' 220 | * @return void 221 | */ 222 | public function import_hsb($color) { 223 | regulate::hsb_array($color); 224 | $this->rgb = convert::hsb_to_rgb($color['h'], $color['s'], $color['b']); 225 | $this->hsl = new hsl($this->rgb); 226 | $this->hex = convert::rgb_to_hex($this->rgb['r'], $this->rgb['g'], $this->rgb['b']); 227 | $this->import_alpha($color); 228 | } 229 | 230 | /** 231 | * Converts a hexadecimal string into an RGB array and imports it. 232 | * 233 | * @param string $color Hexadecimal string 234 | * @return void 235 | */ 236 | public function import_hex($color) { 237 | regulate::hex($color); 238 | $this->import_rgb(convert::hex_to_rgb($color)); 239 | } 240 | 241 | /** 242 | * Converts an integer to a hexadecimal string and imports it. 243 | * 244 | * @param int $color An integer 245 | * @return void 246 | */ 247 | public function import_int($color) { 248 | regulate::hex_int($color); 249 | $this->import_hex(str_pad(base_convert($color, 10, 16), 6, '0', STR_PAD_LEFT)); 250 | } 251 | 252 | /** 253 | * Imports a CMYK array 254 | * 255 | * @param array $color Array with offsets 'c', 'm', 'y', 'k' 256 | * @return void 257 | */ 258 | public function import_cmyk($color) { 259 | regulate::cmyk_array($color); 260 | $this->import_rgb(convert::cmyk_to_rgb($color['c'], $color['m'], $color['y'], $color['k'])); 261 | $this->import_alpha($color); 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /php5/convert.php: -------------------------------------------------------------------------------- 1 | hexdec(substr($hex, 0, 2)), 27 | 'g' => hexdec(substr($hex, 2, 2)), 28 | 'b' => hexdec(substr($hex, 4, 2)) 29 | ); 30 | } 31 | 32 | /** 33 | * Convert a RBA array to a hex string 34 | * 35 | * @param int $r The red value (0 - 255) 36 | * @param int $g The green value (0 - 255) 37 | * @param int $b The blue value (0 - 255) 38 | * @return string The resulting hex string 39 | */ 40 | public static function rgb_to_hex($r = 0, $g = 0, $b = 0) { 41 | return strtoupper( 42 | str_pad(dechex($r), 2, '0', STR_PAD_LEFT) 43 | .str_pad(dechex($g), 2, '0', STR_PAD_LEFT) 44 | .str_pad(dechex($b), 2, '0', STR_PAD_LEFT) 45 | ); 46 | } 47 | 48 | /** 49 | * Convert a RBA array to a CMYK array 50 | * 51 | * @param float $r The red value (0 - 255) 52 | * @param float $g The green value (0 - 255) 53 | * @param float $b The blue value (0 - 255) 54 | * @return array The resulting CMYK array 55 | */ 56 | public static function rgb_to_cmyk($r = 0.0, $g = 0.0, $b = 0.0) { 57 | $c = (255 - $r) / 255 * 100; 58 | $m = (255 - $g) / 255 * 100; 59 | $y = (255 - $b) / 255 * 100; 60 | $k = min(array($c,$m,$y)); 61 | $c -= $k; 62 | $m -= $k; 63 | $y -= $k; 64 | return array( 65 | 'c' => round($c), 66 | 'm' => round($m), 67 | 'y' => round($y), 68 | 'k' => round($k) 69 | ); 70 | } 71 | 72 | /** 73 | * Convert a CMYK array to a RGB array 74 | * 75 | * @param float $c The cyan value (0 - 100) 76 | * @param float $m The magenta value (0 - 100) 77 | * @param float $y The yellow value (0 - 100) 78 | * @param float $k The key (black) value (0 - 100) 79 | * @return array The resulting RGB array 80 | */ 81 | public static function cmyk_to_rgb($c = 0.0, $m = 0.0, $y = 0.0, $k = 0.0) { 82 | $c /= 100; 83 | $m /= 100; 84 | $y /= 100; 85 | $k /= 100; 86 | $r = 1 - min(1, $c * (1 - $k) + $k); 87 | $g = 1 - min(1, $m * (1 - $k) + $k); 88 | $b = 1 - min(1, $y * (1 - $k) + $k); 89 | return array( 90 | 'r' => round($r * 255), 91 | 'g' => round($g * 255), 92 | 'b' => round($b * 255) 93 | ); 94 | } 95 | 96 | /** 97 | * Convert a RGB array to a HSL array 98 | * 99 | * @param float $r The red value (0 - 255) 100 | * @param float $g The green value (0 - 255) 101 | * @param float $b The blue value (0 - 255) 102 | * @return array The resulting HSL array 103 | */ 104 | public static function rgb_to_hsl($r = 0, $g = 0, $b = 0, $accuracy = 2) { 105 | $r /= 255; 106 | $g /= 255; 107 | $b /= 255; 108 | $min = min($r, $g, $b); 109 | $max = max($r, $g, $b); 110 | $delta = $max - $min; 111 | $h = 0; 112 | $s = 0; 113 | $l = ($max + $min) / 2; 114 | 115 | if ($max != $min) { 116 | $s = $delta / ($max + $min); 117 | if ($l >= 0.5) { 118 | $s = $delta / (2 - $max - $min); 119 | } 120 | static::_rgbhsl_hue($h, $r, $g, $b, $max, $delta); 121 | } 122 | 123 | return array( 124 | 'h' => round($h * 360, $accuracy), 125 | 's' => round($s * 100, $accuracy), 126 | 'l' => round($l * 100, $accuracy) 127 | ); 128 | } 129 | 130 | /** 131 | * Color delta algorithm 132 | * 133 | * @param float $rgb The R, G, or B value 134 | * @param float $max The max RGB value 135 | * @param float $delta The delta value ($max - $min) 136 | * @return float The color delta 137 | */ 138 | protected static function _rgbhsl_delta_rgb($rgb, $max, $delta) { 139 | return ((($max - $rgb) / 6) + ($delta / 2)) / $delta; 140 | } 141 | 142 | /** 143 | * Calculate the hue as a percentage from RGB 144 | * 145 | * @param float &$h The variable to modify as hue 146 | * @param float $r The red value as a percentage 147 | * @param float $g The green value as a percentage 148 | * @param float $b The blue value as a percentage 149 | * @param float $max The max RGB value 150 | * @param float $delta The delta value ($max - $min) 151 | * @return void 152 | */ 153 | protected static function _rgbhsl_hue(&$h, $r, $g, $b, $max, $delta) { 154 | $delta_r = static::_rgbhsl_delta_rgb($r, $max, $delta); 155 | $delta_g = static::_rgbhsl_delta_rgb($g, $max, $delta); 156 | $delta_b = static::_rgbhsl_delta_rgb($b, $max, $delta); 157 | 158 | $h = (2 / 3) + $delta_g - $delta_r; 159 | if ($r == $max) { 160 | $h = $delta_b - $delta_g; 161 | } elseif ($g == $max) { 162 | $h = (1 / 3) + $delta_r - $delta_b; 163 | } 164 | if ($h < 0) { 165 | $h++; 166 | } 167 | } 168 | 169 | /** 170 | * Convert a HSL array to a RGB array 171 | * 172 | * @param float $h The hue value (0 - 360) 173 | * @param float $s The saturation value (0 - 100) 174 | * @param float $l The light value (0 - 100) 175 | * @return array The resulting RGB array 176 | */ 177 | public static function hsl_to_rgb($h = 0.0, $s = 0.0, $l = 0.0) { 178 | $s /= 100; 179 | $l /= 100; 180 | $c = (1 - abs((2 * $l) - 1)) * $s; 181 | $x = $c * (1 - abs(fmod(($h / 60), 2) - 1)); 182 | $m = $l - ($c / 2); 183 | $r = $c; 184 | $g = 0; 185 | $b = $x; 186 | 187 | if ($h < 180) { 188 | self::_hslrgb_low($r, $g, $b, $c, $x, $h); 189 | } elseif ($h < 300) { 190 | self::_hslrgb_high($r, $g, $b, $c, $x, $h); 191 | } 192 | 193 | return array( 194 | 'r' => (int) round(($r + $m) * 255), 195 | 'g' => (int) round(($g + $m) * 255), 196 | 'b' => (int) round(($b + $m) * 255) 197 | ); 198 | } 199 | 200 | /** 201 | * Handle low hue values 202 | * 203 | * @param float &$r The red value to modify 204 | * @param float &$g The green value to modify 205 | * @param float &$b The blue value to modify 206 | * @param float $c Potential R, G, or B value 207 | * @param float $x Potential R, G, or B value 208 | * @param float $h The hue 209 | * @return void 210 | */ 211 | private static function _hslrgb_low(&$r, &$g, &$b, $c, $x, $h) { 212 | if ($h < 60) { 213 | $r = $c; 214 | $g = $x; 215 | $b = 0; 216 | } elseif ($h < 120) { 217 | $r = $x; 218 | $g = $c; 219 | $b = 0; 220 | } else { 221 | $r = 0; 222 | $g = $c; 223 | $b = $x; 224 | } 225 | } 226 | 227 | /** 228 | * Handle high hue values 229 | * 230 | * @param float &$r The red value to modify 231 | * @param float &$g The green value to modify 232 | * @param float &$b The blue value to modify 233 | * @param float $c Potential R, G, or B value 234 | * @param float $x Potential R, G, or B value 235 | * @param float $h The hue 236 | * @return void 237 | */ 238 | private static function _hslrgb_high(&$r, &$g, &$b, $c, $x, $h) { 239 | if ($h < 240) { 240 | $r = 0; 241 | $g = $x; 242 | $b = $c; 243 | } else { 244 | $r = $x; 245 | $g = 0; 246 | $b = $c; 247 | } 248 | } 249 | 250 | /** 251 | * Convert a RGB array to a HSB array 252 | * 253 | * @param float $r The red value (0 - 255) 254 | * @param float $g The green value (0 - 255) 255 | * @param float $b The blue value (0 - 255) 256 | * @return array The resulting HSB array 257 | */ 258 | public static function rgb_to_hsb($r = 0.0, $g = 0.0, $b = 0.0, $accuracy = 3) { 259 | $r /= 255; 260 | $g /= 255; 261 | $b /= 255; 262 | 263 | $max = max($r, $g, $b); 264 | $min = min($r, $g, $b); 265 | $v = $max; 266 | $d = $max - $min; 267 | $s = regulate::div($d, $max); 268 | $h = 0; // achromatic 269 | if ($max != $min) { 270 | static::_rgbhsl_hue($h, $r, $g, $b, $max, $d); 271 | } 272 | 273 | $h = round($h * 360, $accuracy); 274 | $s = round($s * 100, $accuracy); 275 | $v = round($v * 100, $accuracy); 276 | 277 | return array('h' => $h, 's' => $s, 'b' => $v); 278 | } 279 | 280 | /** 281 | * Convert a HSB array to a RGB array 282 | * 283 | * @param float $h The hue value (0 - 360) 284 | * @param float $s The saturation value (0 - 100) 285 | * @param float $b The brightness value (0 - 100) 286 | * @return array The resulting RGB array 287 | */ 288 | public static function hsb_to_rgb($h = 0.0, $s = 0.0, $v = 0.0, $accuracy = 3) { 289 | if ($v == 0) { 290 | return array('r' => 0, 'g' => 0, 'b' => 0); 291 | } 292 | $s /= 100; 293 | $v /= 100; 294 | $h /= 60; 295 | $i = floor($h); 296 | $f = $h - $i; 297 | $p = $v * (1 - $s); 298 | $q = $v * (1 - ($s * $f)); 299 | $t = $v * (1 - ($s * (1 - $f))); 300 | $calc = array(array($v, $t, $p), array($q, $v, $p), array($p, $v, $t), array($p, $q, $v), array($t, $p, $v), array($v, $p, $q)); 301 | return array('r' => round($calc[$i][0] * 255, $accuracy), 'g' => round($calc[$i][1] * 255, $accuracy), 'b' => round($calc[$i][2] * 255, $accuracy)); 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /php5/css.php: -------------------------------------------------------------------------------- 1 | alpha() == 100 && !static::$force_alpha) { 29 | return static::hex($color->rgb['r'], $color->rgb['g'], $color->rgb['b']); 30 | } 31 | return static::rgb($color->rgb['r'], $color->rgb['g'], $color->rgb['b'], $color->alpha()); 32 | } 33 | 34 | /** 35 | * Force $color to be an instance of color 36 | * 37 | * @param mixed &$color The color 38 | * @return void 39 | */ 40 | protected static function _color_instance(&$color) { 41 | if (!is_a($color, __CLASS__)) { 42 | $color = new color($color); 43 | } 44 | } 45 | 46 | /** 47 | * Convert and RGB value to a CSS hex string 48 | * 49 | * @param float $r The red value 50 | * @param float $g The green value 51 | * @param float $b The blue value 52 | * @return string The CSS string 53 | */ 54 | public static function hex($r, $g, $b) { 55 | return '#'.convert::rgb_to_hex($r, $g, $b); 56 | } 57 | 58 | /** 59 | * Convert and RGB value to a CSS rgb or rgba string 60 | * 61 | * @param float $r The red value 62 | * @param float $g The green value 63 | * @param float $b The blue value 64 | * @return string The CSS string 65 | */ 66 | public static function rgb($r, $g, $b, $a = 1.0) { 67 | if ($a == 1.0 && !static::$force_alpha) { 68 | return sprintf('rgb(%s,%s,%s)', $r, $g, $b); 69 | } 70 | return sprintf('rgba(%s,%s,%s,%s)', $r, $g, $b, $a / 100); 71 | } 72 | 73 | /** 74 | * Convert and HSL value to a CSS hsl or hsla string 75 | * 76 | * @param float $h The hue value 77 | * @param float $s The saturation value 78 | * @param float $l The light value 79 | * @return string The CSS string 80 | */ 81 | public static function hsl($h, $s, $l, $a = 1.0) { 82 | if ($a == 1.0 && !static::$force_alpha) { 83 | return sprintf('hsl(%s,%s%%,%s%%)', $h, $s, $l); 84 | } 85 | return sprintf('hsla(%s,%s%%,%s%%,%s)', $h, $s, $l, $a / 100); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /php5/error.php: -------------------------------------------------------------------------------- 1 | ($r < 128) ? 255 : 0, 24 | 'g' => ($g < 128) ? 255 : 0, 25 | 'b' => ($b < 128) ? 255 : 0 26 | ); 27 | } 28 | 29 | /** 30 | * Generate the mathematical opposite color for any RGB color 31 | * 32 | * @param int $r The red value 33 | * @param int $g The green value 34 | * @param int $b The blue value 35 | * @return array The mathematical opposite color as an RGB array 36 | */ 37 | public static function rgb_invert($r = 0, $g = 0, $b = 0) { 38 | return array( 39 | 'r' => 255 - $r, 40 | 'g' => 255 - $g, 41 | 'b' => 255 - $b 42 | ); 43 | } 44 | 45 | /** 46 | * Generate the YIQ score for an RGB color 47 | * 48 | * @param int $r The red value 49 | * @param int $g The green value 50 | * @param int $b The blue value 51 | * @return float The YIQ score 52 | */ 53 | public static function yiq_score($r = 0, $g = 0, $b = 0) { 54 | return (($r * 299) + ($g * 587) + ($b * 114)) / 1000; 55 | } 56 | 57 | /** 58 | * Generate a random RGB color 59 | * 60 | * @param int $min_r The min red to allow 61 | * @param int $max_r The max red to allow 62 | * @param int $min_g The min green to allow 63 | * @param int $max_g The max green to allow 64 | * @param int $min_b The min blue to allow 65 | * @param int $max_b The max blue to allow 66 | * @return array The resulting color as a RGB array 67 | */ 68 | public static function rgb_rand($min_r = 0, $max_r = 255, $min_g = 0, $max_g = 255, $min_b = 0, $max_b = 255) { 69 | return array( 70 | 'r' => rand(abs((int) $min_r) % 256, abs((int) $max_r) % 256), 71 | 'g' => rand(abs((int) $min_g) % 256, abs((int) $max_g) % 256), 72 | 'b' => rand(abs((int) $min_b) % 256, abs((int) $max_b) % 256) 73 | ); 74 | } 75 | 76 | /** 77 | * Generate a random HSL color 78 | * 79 | * @param int $min_r The min hue to allow 80 | * @param int $max_r The max hue to allow 81 | * @param int $min_g The min saturation to allow 82 | * @param int $max_g The max saturation to allow 83 | * @param int $min_b The min light to allow 84 | * @param int $max_b The max light to allow 85 | * @return array The resulting color as a HSL array 86 | */ 87 | public static function hsl_rand($min_h = 0, $max_h = 359, $min_s = 0, $max_s = 100, $min_l = 0, $max_l = 100) { 88 | return array( 89 | 'h' => rand(abs((int) $min_h) % 360, abs((int) $max_h) % 360), 90 | 's' => rand(abs((int) $min_s) % 101, abs((int) $max_s) % 101), 91 | 'l' => rand(abs((int) $min_l) % 101, abs((int) $max_l) % 101) 92 | ); 93 | } 94 | 95 | /** 96 | * Blend 2 RGB colors 97 | * 98 | * @param float $r1 The red value from color 1 99 | * @param float $g1 The green value from color 1 100 | * @param float $b1 The blue value from color 1 101 | * @param float $a1 The alpha value from color 1 102 | * @param float $r2 The red value from color 2 103 | * @param float $g2 The green value from color 2 104 | * @param float $b2 The blue value from color 2 105 | * @param float $a2 The alpha value from color 2 106 | * @param float $amount The percentage of color 2 to mix in (defaults to 50 for even blending) 107 | * @return array The resulting color as a RGB array 108 | */ 109 | public static function blend($r1, $g1, $b1, $a1, $r2, $g2, $b2, $a2, $amount = 50.0) { 110 | $x1 = regulate::div(100 - $amount, 100); 111 | $x2 = regulate::div($amount, 100); 112 | return array( 113 | 'r' => round(($r1 * $x1) + ($r2 * $x2), 0), 114 | 'g' => round(($g1 * $x1) + ($g2 * $x2), 0), 115 | 'b' => round(($b1 * $x1) + ($b2 * $x2), 0), 116 | 'a' => ($a1 * $x1) + ($a2 * $x2) 117 | ); 118 | } 119 | 120 | /** 121 | * Generate a gradient range between 2 RGB colors 122 | * 123 | * @param int $r1 The red value from color 1 124 | * @param int $g1 The green value from color 1 125 | * @param int $b1 The blue value from color 1 126 | * @param int $r2 The red value from color 2 127 | * @param int $g2 The green value from color 2 128 | * @param int $b2 The blue value from color 2 129 | * @param int $steps The size of array to produce, 0 will dynamically 130 | * @return array [TODO] 131 | */ 132 | public static function gradient_range($r1 = 0, $g1 = 0, $b1 = 0, $r2 = 0, $g2 = 0, $b2 = 0, $steps = 0) { 133 | $diff = array( 134 | 'r' => $r1 - $r2, 135 | 'g' => $g1 - $g2, 136 | 'b' => $b1 - $b2 137 | ); 138 | $div = max(abs($r1 - $r2), abs($g1 - $g2), abs($b1 - $b2)); 139 | if ($steps != 0) { 140 | $div = abs($steps) - 1; 141 | } 142 | $result = []; 143 | foreach (range(0 , $div) as $i) { 144 | $result[] = array( 145 | 'r' => $r1 + round(regulate::div(-$diff['r'], $div) * $i), 146 | 'g' => $g1 + round(regulate::div(-$diff['g'], $div) * $i), 147 | 'b' => $b1 + round(regulate::div(-$diff['b'], $div) * $i) 148 | ); 149 | } 150 | return $result; 151 | } 152 | 153 | /** 154 | * Round a RGB input to a 'websafe' color hex 155 | * 156 | * @param int $r The red value 157 | * @param int $g The green value 158 | * @param int $b The blue value 159 | * @return string The resulting color as a hex string 160 | */ 161 | public static function web_safe($r = 0, $g = 0, $b = 0) { 162 | return convert::rgb_to_hex( 163 | round($r / 0x33) * 0x33, 164 | round($g / 0x33) * 0x33, 165 | round($b / 0x33) * 0x33 166 | ); 167 | } 168 | 169 | /** 170 | * Converts a hue to the "Y" spectrum 171 | * 172 | * @param float $hue The hue to convert 173 | * @return float The resulting Y 174 | */ 175 | public static function hue_to_yiq($hue) { 176 | if ($hue < 60) { 177 | return $hue * 2.5254237288136; 178 | } elseif ($hue < 180) { 179 | return 150 + ($hue - 60) * 4.9243697478992; 180 | } elseif ($hue < 300) { 181 | return 737 + ($hue - 180) * 0.94957983193277; 182 | } 183 | return 851 + ($hue - 300) * 2.5254237288136; 184 | } 185 | 186 | /** 187 | * Converts a "Y" to the hue spectrum 188 | * 189 | * @param float $yiq The "Y" to convert 190 | * @return float The resulting hue 191 | */ 192 | public static function yiq_to_hue($yiq) { 193 | if ($yiq < 150) { 194 | return $yiq * 0.39597315436242; 195 | } elseif ($yiq < 737) { 196 | return 60 + ($yiq - 150) * 0.20307167235495; 197 | } elseif ($yiq < 851) { 198 | return 180 + ($yiq - 737) * 1.0530973451327; 199 | } 200 | return 300 + ($yiq - 851) * 0.39597315436242; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /php5/hsl.php: -------------------------------------------------------------------------------- 1 | accuracy = $accuracy; 37 | $this->hsl = convert::rgb_to_hsl($rgb_array['r'], $rgb_array['g'], $rgb_array['b'], $this->accuracy); 38 | } 39 | 40 | /** 41 | * Shortcut for return the HSL array 42 | * 43 | * @return array The HSL array 44 | */ 45 | public function __invoke() { 46 | return $this->hsl; 47 | } 48 | 49 | /** 50 | * Check if offset exists in data array 51 | * 52 | * @param string $offset The offset to check 53 | * @return bool TRUE if the offset exist, FALSE otherwise 54 | */ 55 | public function offsetExists($offset) { 56 | return isset($this->hsl[$offset]); 57 | } 58 | 59 | /** 60 | * Get an offset if it exists 61 | * 62 | * @param string $offset The offset to get 63 | * @return mixed The value of the offset 64 | */ 65 | public function offsetGet($offset) { 66 | if ($this->offsetExists($offset)) { 67 | return $this->hsl[$offset]; 68 | } 69 | return error::call(sprintf( 70 | 'The offset "%s" does not exist in %s', 71 | (string) $offset, 72 | __CLASS__ 73 | )); 74 | } 75 | 76 | /** 77 | * Set a value in the data array 78 | * 79 | * @param string $offset The offset to set 80 | * @param mixed $value The value to set it to 81 | * @return mixed The result 82 | */ 83 | public function offsetSet($offset, $value) { 84 | if ($this->offsetExists($offset)) { 85 | return $this->hsl[$offset] = (float) $value; 86 | } 87 | return error::call(sprintf( 88 | 'The offset "%s" cannot be set in %s', 89 | (string) $offset, 90 | __CLASS__ 91 | )); 92 | } 93 | 94 | /** 95 | * Reset an offset to 0 96 | * 97 | * @param string $offset The offset to unset 98 | * @return mixed The result 99 | */ 100 | public function offsetUnset($offset) { 101 | if ($this->offsetExists($offset)) { 102 | return $this->hsl[$offset] = 0.0; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /php5/main_peripheral.php: -------------------------------------------------------------------------------- 1 | color = clone $this->color; 20 | $this->cache = clone $this->cache; 21 | } 22 | 23 | /** 24 | * Custom serialize function 25 | * 26 | * @return string This instance serialized as an RGB string 27 | */ 28 | public function serialize() { 29 | return $this->color->serialize(); 30 | } 31 | 32 | /** 33 | * Custom unserialize function 34 | * 35 | * @param string $serialized This instance serialized as an RGB string 36 | * @return void 37 | */ 38 | public function unserialize($serialized) { 39 | $unserialized = (array) json_decode((string) $serialized); 40 | regulate::rgb_array($unserialized); 41 | $this->set($unserialized, 'rgb'); 42 | } 43 | 44 | /** 45 | * Custom JSON serialize function 46 | * 47 | * @return string This instance serialized as an JSON RGB string 48 | */ 49 | public function jsonSerialize() { 50 | return $this->color->jsonSerialize(); 51 | } 52 | 53 | protected function get_scheme($scheme_name, $return_type = 'hex', $scheme_class) { 54 | if (!is_null($cached = $this->cache->get(get_class($scheme_class).'_'.$scheme_name.'_'.$return_type, $this->hex()))) { 55 | return $cached; 56 | } 57 | $result = static::_scheme($scheme_name, array($scheme_class, strtolower($return_type)), $this->hsl(3)); 58 | $this->cache->set(get_class($scheme_class).'_'.$scheme_name.'_'.$return_type, $this->hex(), $result); 59 | return $result; 60 | } 61 | 62 | /** 63 | * Handles scheme generator callbacks 64 | * 65 | * @param string $scheme_name The name of the scheme algorithm to use 66 | * @param string $callback The return type callback 67 | * @param array $hsl The base color as an HSL array 68 | * @return array The resulting scheme in the proper format, OR an empty array on failure. 69 | */ 70 | protected static function _scheme($scheme_name, $callback, $hsl) { 71 | if (is_callable($callback)) { 72 | return call_user_func($callback, $hsl['h'], $hsl['s'], $hsl['l'], $scheme_name); 73 | } 74 | error::call(sprintf( 75 | 'The $callback "%s" is not a valid callback', 76 | print_r($callback, 1), 77 | __CLASS__, 78 | __FUNCTION__ 79 | )); 80 | return array(); 81 | } 82 | 83 | /** 84 | * Set whether or not caching should be active. 85 | * 86 | * @param bool $active If TRUE caching is turned on, otherwise cashing is turned off. 87 | * @return void 88 | */ 89 | public function cache($active = TRUE) { 90 | $this->cache->active = $active; 91 | } 92 | 93 | /** 94 | * Reset the cache for this instance 95 | * 96 | * @return void 97 | */ 98 | public function reset_cache() { 99 | $this->cache->reset(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /php5/modify.php: -------------------------------------------------------------------------------- 1 | rgb); 19 | $scope = strtolower($scope); 20 | $adjustment = max(min($adjustment, 255), 0 - 255); // Force valid range 21 | $adjustment = static::_convert_to_exact($adjustment, 255, $as_percentage); 22 | $current[$scope] = static::_convert_to_abs($current[$scope], $adjustment, $set_absolute, 0, 255); 23 | return static::regenerate_rgb($color, $current); 24 | } 25 | 26 | public static function hsl($color, $scope, $adjustment, $as_percentage, $set_absolute) { 27 | $current = array_combine(array('hue', 'saturation', 'light'), $color->hsl()); 28 | $scope = strtolower($scope); 29 | $max = 100; 30 | if ($scope == 'hue') { 31 | $max = 359; 32 | } 33 | $adjustment = max(min($adjustment, $max), 0 - $max); // Force valid range 34 | $adjustment = static::_convert_to_exact($adjustment, $max, $as_percentage); 35 | $current[$scope] = static::_convert_to_abs($current[$scope], $adjustment, $set_absolute, 0, $max); 36 | return static::regenerate_hsl($color, $current); 37 | } 38 | 39 | protected static function _convert_to_exact($adjustment, $max, $as_percentage) { 40 | if ($as_percentage) { 41 | return ($adjustment / 100) * abs($max); 42 | } 43 | return $adjustment; 44 | } 45 | 46 | protected static function _convert_to_abs($current, $adjustment, $set_absolute, $min = 0, $max = PHP_INT_MAX) { 47 | if ($set_absolute) { 48 | return abs($adjustment); 49 | } 50 | return max(min($current + $adjustment, $max), $min); 51 | } 52 | 53 | protected static function regenerate_rgb($color, $update) { 54 | $color->import_rgb(array( 55 | 'r' => $update['red'], 56 | 'g' => $update['green'], 57 | 'b' => $update['blue'] 58 | )); 59 | } 60 | 61 | protected static function regenerate_hsl($color, $update) { 62 | $color->import_hsl(array( 63 | 'h' => $update['hue'], 64 | 's' => $update['saturation'], 65 | 'l' => $update['light'] 66 | )); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /php5/regulate.php: -------------------------------------------------------------------------------- 1 | 000000) 166 | * 167 | * @param string &$hex_str The hex string to modify 168 | * @return void 169 | */ 170 | public static function _expand_shorthand(&$hex_str) { 171 | if (strlen($hex_str) === 3) { 172 | $r = $hex_str[0]; 173 | $g = $hex_str[1]; 174 | $b = $hex_str[2]; 175 | $hex_str = $r.$r.$g.$g.$b.$b; 176 | } 177 | } 178 | 179 | /** 180 | * Verify that the hex string is actually a hex string. If not force it to 181 | * '000000' 182 | * 183 | * @param string &$hex_str The hex string to modify 184 | * @return void 185 | */ 186 | public static function _validate_hex_str(&$hex_str) { 187 | if (is_string($hex_str) && preg_match('/\A#?(?:[0-9a-f]{3}|[0-9a-f]{6})\Z/i', $hex_str)) { 188 | return; 189 | } 190 | error::call(sprintf( 191 | 'The input of %s::%s() was not a valid hex string, forcing value to 000000', 192 | __CLASS__, 193 | __FUNCTION__ 194 | )); 195 | $hex_str = '000000'; 196 | } 197 | 198 | /** 199 | * Force an array to have specific lower-case keys. If the array is an indexed 200 | * array and the keys are provided, convert it to an associative array. 201 | * 202 | * @param array &$array The array to be modified 203 | * @return void 204 | */ 205 | public static function standardize_array(&$array, $keys = array()) { 206 | if (!empty($keys) && array_keys($array) === range(0, count($array) - 1) && count($array) == count($keys)) { 207 | $array = array_combine($keys, $array); 208 | } else { 209 | $array = array_change_key_case($array) + array_fill_keys($keys, 0); 210 | } 211 | } 212 | 213 | /** 214 | * Absolute and divide any number so it fits between 0 and $max 215 | * 216 | * @param float $number The original number 217 | * @param float $max The maximum value $number should be 218 | * @return float The resulting number as a float 219 | */ 220 | public static function max($number, $max) { 221 | $max = abs($max); 222 | if ($number > $max) { 223 | $number -= floor($number / ($max + 1)) * ($max + 1); 224 | } 225 | return $number; 226 | } 227 | 228 | /** 229 | * Simple dividing method to handle division by 0 230 | * 231 | * @param float $number The number to divide 232 | * @param float $divisor The number to divide by 233 | * @return float The result 234 | */ 235 | public static function div($number, $divisor) { 236 | if ($divisor == 0) { 237 | return 0; 238 | } 239 | return $number / $divisor; 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /php5/yiq_scheme.php: -------------------------------------------------------------------------------- 1 | &$hsl) { 189 | if ($i == 0) { 190 | $org = $hsl['h']; 191 | continue; 192 | } 193 | $hsl['h'] = static::yiq_adjust($org, $hsl['h'] - $org); 194 | } 195 | 196 | return $scheme; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /phpunit-scrutinizer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | testing/tests 5 | 6 | 7 | 8 | 9 | src 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /phpunit-travis.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | testing/tests 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | testing/tests 5 | 6 | 7 | 8 | 9 | src 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/check.php: -------------------------------------------------------------------------------- 1 | = $check_score returns FALSE, otherwise TRUE 22 | */ 23 | public static function is_dark(int $r = 0, int $g = 0, int $b = 0, int $check_score = 128) :bool { 24 | if (generate::yiq_score($r, $g, $b) >= $check_score) { 25 | return FALSE; 26 | } 27 | return TRUE; 28 | } 29 | 30 | /** 31 | * Measures the visual contrast of 2 RGB colors. 32 | * 33 | * NOTE: most colors do not have a 100% contrasting opposite, but all colors 34 | * do have a contrasting opposite that is at least 50%. 35 | * 36 | * @param array $rgb1 The first color, array where offsets 'r', 'g', & 'b' contain their respective values. 37 | * @param array $rgb2 The second color, array where offsets 'r', 'g', & 'b' contain their respective values. 38 | * @return float The visual contrast as a percentage (e.g. 12.345) 39 | */ 40 | public static function rgb_contrast($rgb1, $rgb2) { 41 | $r = (max($rgb1['r'], $rgb2['r']) - min($rgb1['r'], $rgb2['r'])) * 299; 42 | $g = (max($rgb1['g'], $rgb2['g']) - min($rgb1['g'], $rgb2['g'])) * 587; 43 | $b = (max($rgb1['b'], $rgb2['b']) - min($rgb1['b'], $rgb2['b'])) * 114; 44 | // Sum => Average => Convert to percentage 45 | return ($r + $g + $b) / 1000 / 2.55; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/convert/cmyk.php: -------------------------------------------------------------------------------- 1 | 0, 17 | 'm' => 0, 18 | 'y' => 0, 19 | 'k' => 0 20 | ); 21 | 22 | public static function to_rgb($input) :array { 23 | $cmyk = static::_validate_array_input($input); 24 | $cmyk['c'] /= 100; 25 | $cmyk['m'] /= 100; 26 | $cmyk['y'] /= 100; 27 | $cmyk['k'] /= 100; 28 | $r = 1 - min(1, $cmyk['c'] * (1 - $cmyk['k']) + $cmyk['k']); 29 | $g = 1 - min(1, $cmyk['m'] * (1 - $cmyk['k']) + $cmyk['k']); 30 | $b = 1 - min(1, $cmyk['y'] * (1 - $cmyk['k']) + $cmyk['k']); 31 | return [ 32 | 'r' => round($r * 255), 33 | 'g' => round($g * 255), 34 | 'b' => round($b * 255) 35 | ]; 36 | } 37 | 38 | public static function to_hex($input) :string { 39 | return rgb::to_hex(static::to_rgb($input)); 40 | } 41 | 42 | public static function to_cmyk($input) :array { 43 | return static::_validate_array_input($input); 44 | } 45 | 46 | public static function to_hsl($input) :array { 47 | return rgb::to_hsl(static::to_rgb($input)); 48 | } 49 | 50 | public static function to_hsb($input) :array { 51 | return rgb::to_hsb(static::to_rgb($input)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/convert/hex.php: -------------------------------------------------------------------------------- 1 | hexdec(substr($hex, 0, 2)), 14 | 'g' => hexdec(substr($hex, 2, 2)), 15 | 'b' => hexdec(substr($hex, 4, 2)) 16 | ]; 17 | } 18 | 19 | public static function to_hex($input) :string { 20 | return static::_validate_hex_input($input); 21 | } 22 | 23 | public static function to_cmyk($input) :array { 24 | return rgb::to_cmyk(static::to_rgb($input)); 25 | } 26 | 27 | public static function to_hsl($input) :array { 28 | return rgb::to_hsl(static::to_rgb($input)); 29 | } 30 | 31 | public static function to_hsb($input) :array { 32 | return rgb::to_hsb(static::to_rgb($input)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/convert/hsb.php: -------------------------------------------------------------------------------- 1 | 0, 16 | 's' => 0, 17 | 'b' => 0 18 | ); 19 | 20 | public static function to_rgb($input) :array { 21 | $hsb = static::_validate_array_input($input); 22 | if ($hsb['b'] == 0) { 23 | return ['r' => 0, 'g' => 0, 'b' => 0]; 24 | } 25 | $hsb['h'] /= 60; 26 | $hsb['s'] /= 100; 27 | $hsb['b'] /= 100; 28 | $i = floor($hsb['h']); 29 | $f = $hsb['h'] - $i; 30 | $p = $hsb['b'] * (1 - $hsb['s']); 31 | $q = $hsb['b'] * (1 - ($hsb['s'] * $f)); 32 | $t = $hsb['b'] * (1 - ($hsb['s'] * (1 - $f))); 33 | $calc = [[$hsb['b'], $t, $p],[$q, $hsb['b'], $p],[$p, $hsb['b'], $t],[$p, $q, $hsb['b']],[$t, $p, $hsb['b']],[$hsb['b'], $p, $q]]; 34 | return ['r' => $calc[$i][0] * 255, 'g' => $calc[$i][1] * 255, 'b' => $calc[$i][2] * 255]; 35 | } 36 | 37 | public static function to_hex($input) :string { 38 | return rgb::to_hex(static::to_rgb($input)); 39 | } 40 | 41 | public static function to_cmyk($input) :array { 42 | return rgb::to_cmyk(static::to_rgb($input)); 43 | } 44 | 45 | public static function to_hsl($input) :array { 46 | return rgb::to_hsl(static::to_rgb($input)); 47 | } 48 | 49 | public static function to_hsb($input) :array { 50 | return static::_validate_array_input($input); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/convert/hsl.php: -------------------------------------------------------------------------------- 1 | 0, 16 | 's' => 0, 17 | 'l' => 0 18 | ); 19 | 20 | public static function to_rgb($input) :array { 21 | $hsl = static::_validate_array_input($input); 22 | $hsl['s'] /= 100; 23 | $hsl['l'] /= 100; 24 | $c = (1 - abs((2 * $hsl['l']) - 1)) * $hsl['s']; 25 | $x = $c * (1 - abs(fmod(($hsl['h'] / 60), 2) - 1)); 26 | $m = $hsl['l'] - ($c / 2); 27 | $r = $c; 28 | $g = 0; 29 | $b = $x; 30 | 31 | if ($hsl['h'] < 180) { 32 | static::_hslrgb_low($r, $g, $b, $c, $x, $hsl['h']); 33 | } elseif ($hsl['h'] < 300) { 34 | static::_hslrgb_high($r, $g, $b, $c, $x, $hsl['h']); 35 | } 36 | 37 | return [ 38 | 'r' => (int) round(($r + $m) * 255), 39 | 'g' => (int) round(($g + $m) * 255), 40 | 'b' => (int) round(($b + $m) * 255) 41 | ]; 42 | } 43 | 44 | public static function to_hex($input) :string { 45 | return rgb::to_hex(static::to_rgb($input)); 46 | } 47 | 48 | public static function to_cmyk($input) :array { 49 | return rgb::to_cmyk(static::to_rgb($input)); 50 | } 51 | 52 | public static function to_hsl($input) :array { 53 | return static::_validate_array_input($input); 54 | } 55 | 56 | public static function to_hsb($input) :array { 57 | return rgb::to_hsb(static::to_rgb($input)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/convert/rgb.php: -------------------------------------------------------------------------------- 1 | 0, 16 | 'g' => 0, 17 | 'b' => 0 18 | ); 19 | 20 | public static function to_rgb($input) :array { 21 | return static::_validate_array_input($input); 22 | } 23 | 24 | public static function to_hex($input) :string { 25 | $rgb = static::_validate_array_input($input); 26 | return strtoupper( 27 | str_pad(dechex($rgb['r']), 2, '0', STR_PAD_LEFT) 28 | .str_pad(dechex($rgb['g']), 2, '0', STR_PAD_LEFT) 29 | .str_pad(dechex($rgb['b']), 2, '0', STR_PAD_LEFT) 30 | ); 31 | } 32 | 33 | public static function to_cmyk($input) :array { 34 | $rgb = static::_validate_array_input($input); 35 | $rgbp = array( 36 | 'r' => $rgb['r'] / 255 * 100, 37 | 'g' => $rgb['g'] / 255 * 100, 38 | 'b' => $rgb['b'] / 255 * 100 39 | ); 40 | $k = 100 - max($rgbp); 41 | return [ 42 | 'c' => ((100 - $rgbp['r'] - $k) / (100 - $k)) * 100, 43 | 'm' => ((100 - $rgbp['g'] - $k) / (100 - $k)) * 100, 44 | 'y' => ((100 - $rgbp['b'] - $k) / (100 - $k)) * 100, 45 | 'k' => $k 46 | ]; 47 | } 48 | 49 | public static function to_hsl($input) :array { 50 | $rgb = static::_validate_array_input($input); 51 | $r = $rgb['r'] / 255; 52 | $g = $rgb['g'] / 255; 53 | $b = $rgb['b'] / 255; 54 | $min = min($r, $g, $b); 55 | $max = max($r, $g, $b); 56 | $delta = $max - $min; 57 | $h = 0; 58 | $s = 0; 59 | $l = ($max + $min) / 2; 60 | 61 | if ($max != $min) { 62 | $s = $delta / ($max + $min); 63 | if ($l >= 0.5) { 64 | $s = $delta / (2 - $max - $min); 65 | } 66 | static::_rgbhsl_hue($h, $r, $g, $b, $max, $delta); 67 | } 68 | 69 | return [ 70 | 'h' => $h * 360, 71 | 's' => $s * 100, 72 | 'l' => $l * 100 73 | ]; 74 | } 75 | 76 | public static function to_hsb($input) :array { 77 | $rgb = static::_validate_array_input($input); 78 | $r = $rgb['r'] / 255; 79 | $g = $rgb['g'] / 255; 80 | $b = $rgb['b'] / 255; 81 | 82 | $max = max($r, $g, $b); 83 | $min = min($r, $g, $b); 84 | $v = $max; 85 | $d = $max - $min; 86 | $s = \projectcleverweb\color\regulate::div($d, $max); 87 | $h = 0; // achromatic 88 | if ($max != $min) { 89 | static::_rgbhsl_hue($h, $r, $g, $b, $max, $d); 90 | } 91 | 92 | $h = $h * 360; 93 | $s = $s * 100; 94 | $v = $v * 100; 95 | 96 | return ['h' => $h, 's' => $s, 'b' => $v]; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/css.php: -------------------------------------------------------------------------------- 1 | &$val) { 33 | $val = (float) filter_var($val, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_THOUSAND | FILTER_FLAG_ALLOW_SCIENTIFIC | FILTER_FLAG_ALLOW_FRACTION); 34 | if ($key == 'a') { 35 | $val = $val * 100; 36 | } 37 | } 38 | return $color; 39 | } 40 | 41 | /** 42 | * Choose the best way to represent the color as a CSS value. Will use either 43 | * a hex or rgba value depending on the alpha value. 44 | * 45 | * @param mixed $color The color 46 | * @return string The CSS value 47 | */ 48 | public static function best($color) { 49 | static::_color_instance($color); 50 | if ($color->alpha() == 100 && !static::$force_alpha) { 51 | return static::hex($color->rgb['r'], $color->rgb['g'], $color->rgb['b']); 52 | } 53 | return static::rgb($color->rgb['r'], $color->rgb['g'], $color->rgb['b'], $color->alpha()); 54 | } 55 | 56 | /** 57 | * Force $color to be an instance of color 58 | * 59 | * @param mixed &$color The color 60 | * @return void 61 | */ 62 | protected static function _color_instance(&$color) { 63 | if (!is_a($color, __CLASS__)) { 64 | $color = new color($color); 65 | } 66 | } 67 | 68 | /** 69 | * Convert and RGB value to a CSS hex string 70 | * 71 | * @param float $r The red value 72 | * @param float $g The green value 73 | * @param float $b The blue value 74 | * @return string The CSS string 75 | */ 76 | public static function hex(float $r, float $g, float $b) { 77 | return '#'.convert::rgb_to_hex($r, $g, $b); 78 | } 79 | 80 | /** 81 | * Convert and RGB value to a CSS rgb or rgba string 82 | * 83 | * @param float $r The red value 84 | * @param float $g The green value 85 | * @param float $b The blue value 86 | * @return string The CSS string 87 | */ 88 | public static function rgb(float $r, float $g, float $b, float $a = 1.0) { 89 | if ($a == 1.0 && !static::$force_alpha) { 90 | return sprintf('rgb(%s,%s,%s)', $r, $g, $b); 91 | } 92 | return sprintf('rgba(%s,%s,%s,%s)', $r, $g, $b, $a / 100); 93 | } 94 | 95 | /** 96 | * Convert and HSL value to a CSS hsl or hsla string 97 | * 98 | * @param float $h The hue value 99 | * @param float $s The saturation value 100 | * @param float $l The light value 101 | * @return string The CSS string 102 | */ 103 | public static function hsl(float $h, float $s, float $l, float $a = 1.0) { 104 | if ($a == 1.0 && !static::$force_alpha) { 105 | return sprintf('hsl(%s,%s%%,%s%%)', $h, $s, $l); 106 | } 107 | return sprintf('hsla(%s,%s%%,%s%%,%s)', $h, $s, $l, $a / 100); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/data/cache.php: -------------------------------------------------------------------------------- 1 | reset(); 30 | $this->active = TRUE; 31 | } 32 | 33 | /** 34 | * Reset the entire cache 35 | * 36 | * @return void 37 | */ 38 | public function reset() { 39 | $this->data = []; 40 | } 41 | 42 | /** 43 | * Store a value in the cache 44 | * 45 | * @param string $func The function trying to store data (should be __FUNCTION__) 46 | * @param string $id The storage ID 47 | * @param mixed $value The value to store 48 | */ 49 | public function set(string $func, string $id, $value) { 50 | if ($this->active) { 51 | $this->data[$func] = [$id => $value]; 52 | } 53 | } 54 | 55 | /** 56 | * Get a value from the cache 57 | * 58 | * @param string $func The function trying to get data (should be __FUNCTION__) 59 | * @param string $id The storage ID 60 | * @return mixed The value stored or NULL 61 | */ 62 | public function get(string $func, string $id) { 63 | if ($this->active && isset($this->data[$func][$id])) { 64 | return $this->data[$func][$id]; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/data/color/space/cmyk.php: -------------------------------------------------------------------------------- 1 | array( 34 | 'name' => 'Cyan', 35 | 'min' => 0, 36 | 'max' => 100, 37 | 'default' => 100, 38 | 'allow_negative' => FALSE, 39 | 'allow_float' => FALSE, 40 | 'overflow_method' => 'limit' 41 | ), 42 | 'm' => array( 43 | 'name' => 'Magenta', 44 | 'min' => 0, 45 | 'max' => 100, 46 | 'default' => 100, 47 | 'allow_negative' => FALSE, 48 | 'allow_float' => FALSE, 49 | 'overflow_method' => 'limit' 50 | ), 51 | 'y' => array( 52 | 'name' => 'Yellow', 53 | 'min' => 0, 54 | 'max' => 100, 55 | 'default' => 100, 56 | 'allow_negative' => FALSE, 57 | 'allow_float' => FALSE, 58 | 'overflow_method' => 'limit' 59 | ), 60 | 'k' => array( 61 | 'name' => 'Black', 62 | 'min' => 0, 63 | 'max' => 100, 64 | 'default' => 100, 65 | 'allow_negative' => FALSE, 66 | 'allow_float' => FALSE, 67 | 'overflow_method' => 'limit' 68 | ) 69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /src/data/color/space/hsb.php: -------------------------------------------------------------------------------- 1 | array( 34 | 'name' => 'Hue', 35 | 'min' => 0, 36 | 'max' => 359, 37 | 'default' => 0, 38 | 'allow_negative' => TRUE, 39 | 'allow_float' => FALSE, 40 | 'overflow_method' => 'loop' 41 | ), 42 | 's' => array( 43 | 'name' => 'Saturation', 44 | 'min' => 0, 45 | 'max' => 100, 46 | 'default' => 0, 47 | 'allow_negative' => FALSE, 48 | 'allow_float' => FALSE, 49 | 'overflow_method' => 'limit' 50 | ), 51 | 'b' => array( 52 | 'name' => 'Brightness', 53 | 'min' => 0, 54 | 'max' => 100, 55 | 'default' => 0, 56 | 'allow_negative' => FALSE, 57 | 'allow_float' => FALSE, 58 | 'overflow_method' => 'limit' 59 | ), 60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /src/data/color/space/hsl.php: -------------------------------------------------------------------------------- 1 | array( 34 | 'name' => 'Hue', 35 | 'min' => 0, 36 | 'max' => 359, 37 | 'default' => 0, 38 | 'allow_negative' => TRUE, 39 | 'allow_float' => FALSE, 40 | 'overflow_method' => 'loop' 41 | ), 42 | 's' => array( 43 | 'name' => 'Saturation', 44 | 'min' => 0, 45 | 'max' => 100, 46 | 'default' => 0, 47 | 'allow_negative' => FALSE, 48 | 'allow_float' => FALSE, 49 | 'overflow_method' => 'limit' 50 | ), 51 | 'l' => array( 52 | 'name' => 'Light', 53 | 'min' => 0, 54 | 'max' => 100, 55 | 'default' => 0, 56 | 'allow_negative' => FALSE, 57 | 'allow_float' => FALSE, 58 | 'overflow_method' => 'limit' 59 | ), 60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /src/data/color/space/rgb.php: -------------------------------------------------------------------------------- 1 | array( 34 | 'name' => 'Red', 35 | 'min' => 0, 36 | 'max' => 255, 37 | 'default' => 0, 38 | 'allow_negative' => FALSE, 39 | 'allow_float' => FALSE, 40 | 'overflow_method' => 'limit' 41 | ), 42 | 'g' => array( 43 | 'name' => 'Green', 44 | 'min' => 0, 45 | 'max' => 255, 46 | 'default' => 0, 47 | 'allow_negative' => FALSE, 48 | 'allow_float' => FALSE, 49 | 'overflow_method' => 'limit' 50 | ), 51 | 'b' => array( 52 | 'name' => 'Blue', 53 | 'min' => 0, 54 | 'max' => 255, 55 | 'default' => 0, 56 | 'allow_negative' => FALSE, 57 | 'allow_float' => FALSE, 58 | 'overflow_method' => 'limit' 59 | ), 60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /src/data/color/type.php: -------------------------------------------------------------------------------- 1 | 'rgb', 47 | 'hls' => 'hsl', 48 | 'bhs' => 'hsb', 49 | 'ckmy' => 'cmyk' 50 | ]; 51 | if (isset($types[$type])) { 52 | return $types[$type]; 53 | } 54 | return 'error'; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/data/color/x11.php: -------------------------------------------------------------------------------- 1 | array('r' => 240, 'g' => 248, 'b' => 255), 23 | 'antiquewhite' => array('r' => 250, 'g' => 235, 'b' => 215), 24 | 'aqua' => array('r' => 0, 'g' => 255, 'b' => 255), 25 | 'aquamarine' => array('r' => 127, 'g' => 255, 'b' => 212), 26 | 'azure' => array('r' => 240, 'g' => 255, 'b' => 255), 27 | 'beige' => array('r' => 245, 'g' => 245, 'b' => 220), 28 | 'bisque' => array('r' => 255, 'g' => 228, 'b' => 196), 29 | 'black' => array('r' => 0, 'g' => 0, 'b' => 0), 30 | 'blanchedalmond' => array('r' => 255, 'g' => 235, 'b' => 205), 31 | 'blue' => array('r' => 0, 'g' => 0, 'b' => 255), 32 | 'blueviolet' => array('r' => 138, 'g' => 43, 'b' => 226), 33 | 'brown' => array('r' => 165, 'g' => 42, 'b' => 42), 34 | 'burlywood' => array('r' => 222, 'g' => 184, 'b' => 135), 35 | 'cadetblue' => array('r' => 95, 'g' => 158, 'b' => 160), 36 | 'chartreuse' => array('r' => 127, 'g' => 255, 'b' => 0), 37 | 'chocolate' => array('r' => 210, 'g' => 105, 'b' => 30), 38 | 'coral' => array('r' => 255, 'g' => 127, 'b' => 80), 39 | 'cornflowerblue' => array('r' => 100, 'g' => 149, 'b' => 237), 40 | 'cornsilk' => array('r' => 255, 'g' => 248, 'b' => 220), 41 | 'crimson' => array('r' => 220, 'g' => 20, 'b' => 60), 42 | 'cyan' => array('r' => 0, 'g' => 255, 'b' => 255), 43 | 'darkblue' => array('r' => 0, 'g' => 0, 'b' => 139), 44 | 'darkcyan' => array('r' => 0, 'g' => 139, 'b' => 139), 45 | 'darkgoldenrod' => array('r' => 184, 'g' => 134, 'b' => 11), 46 | 'darkgray' => array('r' => 169, 'g' => 169, 'b' => 169), 47 | 'darkgreen' => array('r' => 0, 'g' => 100, 'b' => 0), 48 | 'darkgrey' => array('r' => 169, 'g' => 169, 'b' => 169), 49 | 'darkkhaki' => array('r' => 189, 'g' => 183, 'b' => 107), 50 | 'darkmagenta' => array('r' => 139, 'g' => 0, 'b' => 139), 51 | 'darkolivegreen' => array('r' => 85, 'g' => 107, 'b' => 47), 52 | 'darkorange' => array('r' => 255, 'g' => 140, 'b' => 0), 53 | 'darkorchid' => array('r' => 153, 'g' => 50, 'b' => 204), 54 | 'darkred' => array('r' => 139, 'g' => 0, 'b' => 0), 55 | 'darksalmon' => array('r' => 233, 'g' => 150, 'b' => 122), 56 | 'darkseagreen' => array('r' => 143, 'g' => 188, 'b' => 143), 57 | 'darkslateblue' => array('r' => 72, 'g' => 61, 'b' => 139), 58 | 'darkslategray' => array('r' => 47, 'g' => 79, 'b' => 79), 59 | 'darkslategrey' => array('r' => 47, 'g' => 79, 'b' => 79), 60 | 'darkturquoise' => array('r' => 0, 'g' => 206, 'b' => 209), 61 | 'darkviolet' => array('r' => 148, 'g' => 0, 'b' => 211), 62 | 'deeppink' => array('r' => 255, 'g' => 20, 'b' => 147), 63 | 'deepskyblue' => array('r' => 0, 'g' => 191, 'b' => 255), 64 | 'dimgray' => array('r' => 105, 'g' => 105, 'b' => 105), 65 | 'dimgrey' => array('r' => 105, 'g' => 105, 'b' => 105), 66 | 'dodgerblue' => array('r' => 30, 'g' => 144, 'b' => 255), 67 | 'firebrick' => array('r' => 178, 'g' => 34, 'b' => 34), 68 | 'floralwhite' => array('r' => 255, 'g' => 250, 'b' => 240), 69 | 'forestgreen' => array('r' => 34, 'g' => 139, 'b' => 34), 70 | 'fuchsia' => array('r' => 255, 'g' => 0, 'b' => 255), 71 | 'gainsboro' => array('r' => 220, 'g' => 220, 'b' => 220), 72 | 'ghostwhite' => array('r' => 248, 'g' => 248, 'b' => 255), 73 | 'gold' => array('r' => 255, 'g' => 215, 'b' => 0), 74 | 'goldenrod' => array('r' => 218, 'g' => 165, 'b' => 32), 75 | 'gray' => array('r' => 128, 'g' => 128, 'b' => 128), 76 | 'green' => array('r' => 0, 'g' => 128, 'b' => 0), 77 | 'greenyellow' => array('r' => 173, 'g' => 255, 'b' => 47), 78 | 'grey' => array('r' => 128, 'g' => 128, 'b' => 128), 79 | 'honeydew' => array('r' => 240, 'g' => 255, 'b' => 240), 80 | 'hotpink' => array('r' => 255, 'g' => 105, 'b' => 180), 81 | 'indianred' => array('r' => 205, 'g' => 92, 'b' => 92), 82 | 'indigo' => array('r' => 75, 'g' => 0, 'b' => 130), 83 | 'ivory' => array('r' => 255, 'g' => 255, 'b' => 240), 84 | 'khaki' => array('r' => 240, 'g' => 230, 'b' => 140), 85 | 'lavender' => array('r' => 230, 'g' => 230, 'b' => 250), 86 | 'lavenderblush' => array('r' => 255, 'g' => 240, 'b' => 245), 87 | 'lawngreen' => array('r' => 124, 'g' => 252, 'b' => 0), 88 | 'lemonchiffon' => array('r' => 255, 'g' => 250, 'b' => 205), 89 | 'lightblue' => array('r' => 173, 'g' => 216, 'b' => 230), 90 | 'lightcoral' => array('r' => 240, 'g' => 128, 'b' => 128), 91 | 'lightcyan' => array('r' => 224, 'g' => 255, 'b' => 255), 92 | 'lightgoldenrodyellow' => array('r' => 250, 'g' => 250, 'b' => 210), 93 | 'lightgray' => array('r' => 211, 'g' => 211, 'b' => 211), 94 | 'lightgreen' => array('r' => 144, 'g' => 238, 'b' => 144), 95 | 'lightgrey' => array('r' => 211, 'g' => 211, 'b' => 211), 96 | 'lightpink' => array('r' => 255, 'g' => 182, 'b' => 193), 97 | 'lightsalmon' => array('r' => 255, 'g' => 160, 'b' => 122), 98 | 'lightseagreen' => array('r' => 32, 'g' => 178, 'b' => 170), 99 | 'lightskyblue' => array('r' => 135, 'g' => 206, 'b' => 250), 100 | 'lightslategray' => array('r' => 119, 'g' => 136, 'b' => 153), 101 | 'lightslategrey' => array('r' => 119, 'g' => 136, 'b' => 153), 102 | 'lightsteelblue' => array('r' => 176, 'g' => 196, 'b' => 222), 103 | 'lightyellow' => array('r' => 255, 'g' => 255, 'b' => 224), 104 | 'lime' => array('r' => 0, 'g' => 255, 'b' => 0), 105 | 'limegreen' => array('r' => 50, 'g' => 205, 'b' => 50), 106 | 'linen' => array('r' => 250, 'g' => 240, 'b' => 230), 107 | 'magenta' => array('r' => 255, 'g' => 0, 'b' => 255), 108 | 'maroon' => array('r' => 128, 'g' => 0, 'b' => 0), 109 | 'mediumaquamarine' => array('r' => 102, 'g' => 205, 'b' => 170), 110 | 'mediumblue' => array('r' => 0, 'g' => 0, 'b' => 205), 111 | 'mediumorchid' => array('r' => 186, 'g' => 85, 'b' => 211), 112 | 'mediumpurple' => array('r' => 147, 'g' => 112, 'b' => 219), 113 | 'mediumseagreen' => array('r' => 60, 'g' => 179, 'b' => 113), 114 | 'mediumslateblue' => array('r' => 123, 'g' => 104, 'b' => 238), 115 | 'mediumspringgreen' => array('r' => 0, 'g' => 250, 'b' => 154), 116 | 'mediumturquoise' => array('r' => 72, 'g' => 209, 'b' => 204), 117 | 'mediumvioletred' => array('r' => 199, 'g' => 21, 'b' => 133), 118 | 'midnightblue' => array('r' => 25, 'g' => 25, 'b' => 112), 119 | 'mintcream' => array('r' => 245, 'g' => 255, 'b' => 250), 120 | 'mistyrose' => array('r' => 255, 'g' => 228, 'b' => 225), 121 | 'moccasin' => array('r' => 255, 'g' => 228, 'b' => 181), 122 | 'navajowhite' => array('r' => 255, 'g' => 222, 'b' => 173), 123 | 'navy' => array('r' => 0, 'g' => 0, 'b' => 128), 124 | 'oldlace' => array('r' => 253, 'g' => 245, 'b' => 230), 125 | 'olive' => array('r' => 128, 'g' => 128, 'b' => 0), 126 | 'olivedrab' => array('r' => 107, 'g' => 142, 'b' => 35), 127 | 'orange' => array('r' => 255, 'g' => 165, 'b' => 0), 128 | 'orangered' => array('r' => 255, 'g' => 69, 'b' => 0), 129 | 'orchid' => array('r' => 218, 'g' => 112, 'b' => 214), 130 | 'palegoldenrod' => array('r' => 238, 'g' => 232, 'b' => 170), 131 | 'palegreen' => array('r' => 152, 'g' => 251, 'b' => 152), 132 | 'paleturquoise' => array('r' => 175, 'g' => 238, 'b' => 238), 133 | 'palevioletred' => array('r' => 219, 'g' => 112, 'b' => 147), 134 | 'papayawhip' => array('r' => 255, 'g' => 239, 'b' => 213), 135 | 'peachpuff' => array('r' => 255, 'g' => 218, 'b' => 185), 136 | 'peru' => array('r' => 205, 'g' => 133, 'b' => 63), 137 | 'pink' => array('r' => 255, 'g' => 192, 'b' => 203), 138 | 'plum' => array('r' => 221, 'g' => 160, 'b' => 221), 139 | 'powderblue' => array('r' => 176, 'g' => 224, 'b' => 230), 140 | 'purple' => array('r' => 128, 'g' => 0, 'b' => 128), 141 | 'red' => array('r' => 255, 'g' => 0, 'b' => 0), 142 | 'rosybrown' => array('r' => 188, 'g' => 143, 'b' => 143), 143 | 'royalblue' => array('r' => 65, 'g' => 105, 'b' => 225), 144 | 'saddlebrown' => array('r' => 139, 'g' => 69, 'b' => 19), 145 | 'salmon' => array('r' => 250, 'g' => 128, 'b' => 114), 146 | 'sandybrown' => array('r' => 244, 'g' => 164, 'b' => 96), 147 | 'seagreen' => array('r' => 46, 'g' => 139, 'b' => 87), 148 | 'seashell' => array('r' => 255, 'g' => 245, 'b' => 238), 149 | 'sienna' => array('r' => 160, 'g' => 82, 'b' => 45), 150 | 'silver' => array('r' => 192, 'g' => 192, 'b' => 192), 151 | 'skyblue' => array('r' => 135, 'g' => 206, 'b' => 235), 152 | 'slateblue' => array('r' => 106, 'g' => 90, 'b' => 205), 153 | 'slategray' => array('r' => 112, 'g' => 128, 'b' => 144), 154 | 'slategrey' => array('r' => 112, 'g' => 128, 'b' => 144), 155 | 'snow' => array('r' => 255, 'g' => 250, 'b' => 250), 156 | 'springgreen' => array('r' => 0, 'g' => 255, 'b' => 127), 157 | 'steelblue' => array('r' => 70, 'g' => 130, 'b' => 180), 158 | 'tan' => array('r' => 210, 'g' => 180, 'b' => 140), 159 | 'teal' => array('r' => 0, 'g' => 128, 'b' => 128), 160 | 'thistle' => array('r' => 216, 'g' => 191, 'b' => 216), 161 | 'tomato' => array('r' => 255, 'g' => 99, 'b' => 71), 162 | 'turquoise' => array('r' => 64, 'g' => 224, 'b' => 208), 163 | 'violet' => array('r' => 238, 'g' => 130, 'b' => 238), 164 | 'wheat' => array('r' => 245, 'g' => 222, 'b' => 179), 165 | 'white' => array('r' => 255, 'g' => 255, 'b' => 255), 166 | 'whitesmoke' => array('r' => 245, 'g' => 245, 'b' => 245), 167 | 'yellow' => array('r' => 255, 'g' => 255, 'b' => 0), 168 | 'yellowgreen' => array('r' => 154, 'g' => 205, 'b' => 50) 169 | ); 170 | 171 | /** 172 | * Gets a X11 color as RGB if it exists, otherwise returns FALSE. 173 | * 174 | * @param string $color The color name to search for 175 | * @return array|bool Returns a RGB color array if it exists, FALSE otherwise. 176 | */ 177 | public static function get(string $color) { 178 | $color = strtolower(trim($color)); 179 | if (isset(static::$map[$color])) { 180 | return static::$map[$color]; 181 | } 182 | return FALSE; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/data/store.old.php: -------------------------------------------------------------------------------- 1 | hsl)(); 72 | } 73 | 74 | /** 75 | * Serializes this object. 76 | * 77 | * @return string The serialized object 78 | */ 79 | public function serialize() :string { 80 | return json_encode($this->rgb + ['a' => $this->alpha]); 81 | } 82 | 83 | /** 84 | * Unserializes this object. 85 | * 86 | * @param string $serialized The object as a serialized string 87 | * @return void 88 | */ 89 | public function unserialize($serialized) { 90 | $unserialized = (array) json_decode((string) $serialized); 91 | regulate::rgb_array($unserialized); 92 | $this->import_rgb($unserialized); 93 | } 94 | 95 | /** 96 | * Serializes this object into JSON. 97 | * 98 | * @return string The serialized object 99 | */ 100 | public function jsonSerialize() :array { 101 | return $this->rgb + ['a' => $this->alpha]; 102 | } 103 | 104 | /** 105 | * Determine the type of color being used. 106 | * 107 | * @param mized $color The color in question 108 | * @return string The color type as a string, returns 'error' if $color is invalid 109 | */ 110 | public static function get_type($color) :string { 111 | if (is_array($color)) { 112 | return static::_get_array_type($color); 113 | } elseif (is_string($color)) { 114 | // return static::_get_str_type($color); 115 | return 'str'; 116 | } elseif (is_int($color)) { 117 | return 'int'; 118 | } 119 | return 'error'; 120 | } 121 | 122 | protected function _get_str_type(string $color) { 123 | $color = strtolower(str_replace(array(' ', "\t", "\n", "\r", "\0", "\x0B"), '', $color)); 124 | if (regulate::_validate_hex_str($color, TRUE)) { 125 | return 'hex'; 126 | } elseif (css::get($color, FALSE)) { 127 | return 'css'; 128 | } elseif (x11::get($color)) { 129 | return 'x11'; 130 | } 131 | return 'error'; 132 | } 133 | 134 | /** 135 | * Determine the type of color being used if it is an array. 136 | * 137 | * @param array $color The color in question 138 | * @return string The color type as a string, returns 'error' if $color is invalid 139 | */ 140 | protected static function _get_array_type(array $color) :string { 141 | $color = array_change_key_case($color); 142 | unset($color['a']); // ignore alpha channel 143 | ksort($color); 144 | $type = implode('', array_keys($color)); 145 | $types = [ 146 | 'bgr' => 'rgb', 147 | 'hls' => 'hsl', 148 | 'bhs' => 'hsb', 149 | 'ckmy' => 'cmyk' 150 | ]; 151 | if (isset($types[$type])) { 152 | return $types[$type]; 153 | } 154 | return 'error'; 155 | } 156 | 157 | /** 158 | * Get (and set) the alpha channel 159 | * 160 | * @param mixed $new_alpha If numeric, the alpha channel is set to this value 161 | * @return float The current alpha value 162 | */ 163 | public function alpha($new_alpha = NULL) :float { 164 | if (is_numeric($new_alpha)) { 165 | $this->alpha = (float) $new_alpha; 166 | } 167 | return $this->alpha; 168 | } 169 | 170 | /** 171 | * Handles general errors when importing, and forces the input to be valid. 172 | * 173 | * @return void 174 | */ 175 | protected function import_error() { 176 | error::trigger(error::INVALID_COLOR, sprintf( 177 | 'The color supplied to %s\'s constructor was not valid', 178 | __CLASS__ 179 | )); 180 | $this->import_rgb([0, 0, 0]); 181 | } 182 | 183 | /** 184 | * Import the alpha channel from a color array, or create one if it doesn't exist 185 | * 186 | * @param array $color The color array to check 187 | * @return void 188 | */ 189 | protected function import_alpha(array $color) { 190 | if (isset($color['a'])) { 191 | $this->alpha = regulate::max((float) $color['a'], 100); 192 | } else { 193 | $this->alpha = 100.0; 194 | } 195 | } 196 | 197 | /** 198 | * Handles importing of another instance of color 199 | * 200 | * @return void 201 | */ 202 | protected function import_color(data $color) { 203 | $this->rgb = $color->rgb; 204 | $this->hex = $color->hex; 205 | $this->hsl = clone $color->hsl; 206 | $this->alpha = $color->alpha; 207 | } 208 | 209 | /** 210 | * Imports a RGB array. 211 | * 212 | * @param array $color Array with offsets 'r', 'g', 'b' 213 | * @return void 214 | */ 215 | public function import_rgb(array $color) { 216 | regulate::rgb_array($color); 217 | $this->rgb = array_intersect_key($color, ['r' => 0, 'g' => 0, 'b' => 0]); 218 | $this->hex = convert\rgb::to_hex($this->rgb); 219 | $this->hsl = new hsl($this->rgb); 220 | $this->import_alpha($color); 221 | } 222 | 223 | /** 224 | * Imports a hsl array. 225 | * 226 | * @param array $color Array with offsets 'h', 's', 'l' 227 | * @return void 228 | */ 229 | public function import_hsl(array $color) { 230 | regulate::hsl_array($color); 231 | $this->rgb = convert\hsl::to_rgb($color); 232 | $this->hsl = new hsl($this->rgb); // [todo] This should taken from input 233 | $this->hex = convert\rgb::to_hex($this->rgb); 234 | $this->import_alpha($color); 235 | } 236 | 237 | /** 238 | * Imports a hsb array. 239 | * 240 | * @param array $color Array with offsets 'h', 's', 'b' 241 | * @return void 242 | */ 243 | public function import_hsb(array $color) { 244 | regulate::hsb_array($color); 245 | $this->rgb = convert\hsb::to_rgb($color); 246 | $this->hsl = new hsl($this->rgb); 247 | $this->hex = convert\rgb::to_hex($this->rgb); 248 | $this->import_alpha($color); 249 | } 250 | 251 | /** 252 | * Converts a hexadecimal string into an RGB array and imports it. 253 | * 254 | * @param string $color Hexadecimal string 255 | * @return void 256 | */ 257 | public function import_hex(string $color) { 258 | regulate::hex($color); 259 | $this->import_rgb(convert\hex::to_rgb($color)); 260 | } 261 | 262 | public function import_str(string $color) { 263 | $color = strtolower(str_replace(array(' ', "\t", "\n", "\r", "\0", "\x0B"), '', $color)); 264 | if (regulate::_validate_hex_str($color, TRUE)) { 265 | $this->import_hex($color); 266 | return; 267 | } elseif (preg_match('/\A(rgb|hsl)a?\((\d+),(\d+),(\d+)(?:,(\d|\d\.\d?|\.\d+))?\)\Z/i', $color, $match)) { 268 | $this->import_regex($match); 269 | return; 270 | } elseif ($x11 = x11::get($color)) { 271 | $this->import_rgb($x11); 272 | return; 273 | } 274 | $this->import_error(); 275 | } 276 | 277 | public function import_regex(array $match) { 278 | $alpha = 100; 279 | if (isset($match[5])) { 280 | $alpha = (float) $match[5] * 100; 281 | } 282 | $color = array_combine(str_split($match[1].'a'), [$match[2], $match[3], $match[4], $alpha]); 283 | call_user_func([__CLASS__, 'import_'.$match[1]], $color); 284 | } 285 | 286 | /** 287 | * Converts an integer to a hexadecimal string and imports it. 288 | * 289 | * @param int $color An integer 290 | * @return void 291 | */ 292 | public function import_int(int $color) { 293 | regulate::hex_int($color); 294 | $this->import_hex(str_pad(base_convert($color, 10, 16), 6, '0', STR_PAD_LEFT)); 295 | } 296 | 297 | /** 298 | * Imports a CMYK array 299 | * 300 | * @param array $color Array with offsets 'c', 'm', 'y', 'k' 301 | * @return void 302 | */ 303 | public function import_cmyk(array $color) { 304 | regulate::cmyk_array($color); 305 | $this->import_rgb(convert\cmyk::to_rgb($color['c'], $color['m'], $color['y'], $color['k'])); 306 | $this->import_alpha($color); 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /src/data/store.php: -------------------------------------------------------------------------------- 1 | 0, 88 | 'g' => 0, 89 | 'b' => 0 90 | ); 91 | } 92 | if (in_array($type, static::$valid_imports)) { 93 | call_user_func([__CLASS__, 'import_'.$type], $color); 94 | } else { 95 | $this->__set($type, $color); 96 | } 97 | } 98 | 99 | public function __get($key) { 100 | if (!in_array($key, static::$valid_color_spaces)) { 101 | error::trigger(error::INVALID_ARGUMENT, sprintf( 102 | 'Cannot get color space "%s"', 103 | $key 104 | )); 105 | return $this->__get($this->current_space); 106 | } 107 | if (!$this->__isset($key)) { 108 | $this->color_spaces[$key] = static::_get_convert($this->color_spaces, $this->current_space, $key); 109 | } 110 | return (array) $this->color_spaces[$key]; 111 | } 112 | 113 | public function __set($key, $value) { 114 | if (in_array($key, static::$valid_color_spaces)) { 115 | $color_space = __NAMESPACE__.'\\color\\space\\'.$key; 116 | $this->color_spaces[$key] = new $color_space($value); 117 | $this->current_space = $key; 118 | return $this->__get($key); 119 | } 120 | error::trigger(error::INVALID_ARGUMENT, sprintf( 121 | 'Cannot set color space "%s"', 122 | __CLASS__ 123 | )); 124 | } 125 | 126 | public function __isset($key) { 127 | return isset($this->color_spaces[$key]); 128 | } 129 | 130 | public function __unset($key) { 131 | if ($this->__isset($key) && count($this->color_spaces) > 1) { 132 | unset($this->color_spaces); 133 | } elseif ($this->__isset($key)) { 134 | $this->clear('rgb', array( 135 | 'r' => 0, 136 | 'g' => 0, 137 | 'b' => 0 138 | )); 139 | } 140 | } 141 | 142 | protected static function _get_convert(array $color_spaces, string $current, string $to) { 143 | if (isset($color_spaces[$current])) { 144 | $from = $current; 145 | } else { 146 | reset($color_spaces); 147 | $from = key($color_spaces); 148 | $this->current_space = $from; // Original space was unset 149 | } 150 | $convert = call_user_func(array('\\projectcleverweb\\color\\convert\\'.$from, 'to_'.$to), $color_spaces[$from]); 151 | $space = __NAMESPACE__.'\\color\\space\\'.$to; 152 | return new $space($convert); 153 | } 154 | 155 | public function clear_cache() { 156 | 157 | if (is_callable([__CLASS__, 'import_'.$type])) { 158 | call_user_func([__CLASS__, 'import_'.$type], $color); 159 | } else { 160 | error::trigger(); 161 | } 162 | } 163 | 164 | protected function _clear() { 165 | $this->color_spaces = array(); 166 | } 167 | 168 | protected function get_space() { 169 | return $this->current_space; 170 | } 171 | 172 | protected function set_space(string $color_space) :string { 173 | if (in_array(static::$valid_color_spaces)) { 174 | $this->current_space = $color_space; 175 | } 176 | return $this->current_space; 177 | } 178 | 179 | /** 180 | * Serializes this object. 181 | * 182 | * @return string The serialized object 183 | */ 184 | public function serialize() :string { 185 | return json_encode($this->rgb + ['a' => $this->alpha]); 186 | } 187 | 188 | /** 189 | * Unserializes this object. 190 | * 191 | * @param string $serialized The object as a serialized string 192 | * @return void 193 | */ 194 | public function unserialize($serialized) { 195 | $unserialized = (array) json_decode((string) $serialized); 196 | regulate::rgb_array($unserialized); 197 | $this->import_rgb($unserialized); 198 | } 199 | 200 | /** 201 | * Serializes this object into JSON. 202 | * 203 | * @return string The serialized object 204 | */ 205 | public function jsonSerialize() :array { 206 | return $this->color_spaces + ['alpha' => $this->alpha]; 207 | } 208 | 209 | /** 210 | * Handles general errors when importing, and forces the input to be valid. 211 | * 212 | * @return void 213 | */ 214 | protected function import_error() { 215 | error::trigger(error::INVALID_COLOR, sprintf( 216 | 'The color supplied to %s\'s constructor was not valid', 217 | __CLASS__ 218 | )); 219 | $this->import_rgb([0, 0, 0]); 220 | } 221 | 222 | /** 223 | * Import the alpha channel from a color array, or create one if it doesn't exist 224 | * 225 | * @param array $color The color array to check 226 | * @return void 227 | */ 228 | protected function import_alpha(array $color) { 229 | if (isset($color['a'])) { 230 | $this->alpha = regulate::max((float) $color['a'], 100); 231 | } else { 232 | $this->alpha = 100.0; 233 | } 234 | } 235 | 236 | /** 237 | * Handles importing of another instance of color 238 | * 239 | * @return void 240 | */ 241 | protected function import_object(store $color) { 242 | $this->_clear(); 243 | foreach ($this->color_spaces as $space => $data) { 244 | $color_space = __NAMESPACE__.'\\space\\'.$space; 245 | $this->color_spaces[$space] = new $color_space($data); 246 | } 247 | $this->current_space = $color->get_space(); 248 | $this->alpha = $color->alpha; 249 | } 250 | 251 | /** 252 | * Imports a RGB array. 253 | * 254 | * @param array $color Array with offsets 'r', 'g', 'b' 255 | * @return void 256 | */ 257 | public function import_rgb(array $color) { 258 | $this->_clear(); 259 | $this->color_spaces['rgb'] = new color\space\rgb($color); 260 | $this->import_alpha($color); 261 | } 262 | 263 | /** 264 | * Imports a hsl array. 265 | * 266 | * @param array $color Array with offsets 'h', 's', 'l' 267 | * @return void 268 | */ 269 | public function import_hsl(array $color) { 270 | $this->_clear(); 271 | $this->color_spaces['hsl'] = new color\space\hsl($color); 272 | $this->import_alpha($color); 273 | } 274 | 275 | /** 276 | * Imports a hsb array. 277 | * 278 | * @param array $color Array with offsets 'h', 's', 'b' 279 | * @return void 280 | */ 281 | public function import_hsb(array $color) { 282 | $this->_clear(); 283 | $this->color_spaces['hsb'] = new color\space\hsb($color); 284 | $this->import_alpha($color); 285 | } 286 | 287 | /** 288 | * Imports a CMYK array 289 | * 290 | * @param array $color Array with offsets 'c', 'm', 'y', 'k' 291 | * @return void 292 | */ 293 | public function import_cmyk(array $color) { 294 | $this->_clear(); 295 | $this->color_spaces['cmyk'] = new color\space\cmyk($color); 296 | $this->import_alpha($color); 297 | } 298 | 299 | /** 300 | * Converts a hexadecimal string into an RGB array and imports it. 301 | * 302 | * @param string $color Hexadecimal string 303 | * @return void 304 | */ 305 | public function import_hex(string $color) { 306 | $this->import_rgb(convert\hex::to_rgb($color)); 307 | } 308 | 309 | /** 310 | * Converts a hexadecimal string into an RGB array and imports it. 311 | * 312 | * @param string $color Hexadecimal string 313 | * @return void 314 | */ 315 | public function import_css(string $color) { 316 | // result will either be an RGB or HSL array 317 | self::__construct(css::get($color)); 318 | } 319 | 320 | /** 321 | * Converts an integer to a hexadecimal string and imports it. 322 | * 323 | * @param int $color An integer 324 | * @return void 325 | */ 326 | public function import_int(int $color) { 327 | regulate::hex_int($color); 328 | $this->import_hex(str_pad(base_convert($color, 10, 16), 6, '0', STR_PAD_LEFT)); 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /src/data/type.php: -------------------------------------------------------------------------------- 1 | 'rgb', 47 | 'hls' => 'hsl', 48 | 'bhs' => 'hsb', 49 | 'ckmy' => 'cmyk' 50 | ]; 51 | if (isset($types[$type])) { 52 | return $types[$type]; 53 | } 54 | return 'error'; 55 | } 56 | 57 | public static function _object($color) :string { 58 | if (is_object($color) && is_a($color, __NAMESPACE__.'\\store')) { 59 | return 'object'; 60 | } 61 | return 'error'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/error.php: -------------------------------------------------------------------------------- 1 | 'GENERAL', 45 | self::INVALID_CONFIG => 'INVALID_CONFIG', 46 | self::INVALID_VALUE => 'INVALID_VALUE', 47 | self::INVALID_ARGUMENT => 'INVALID_ARGUMENT', 48 | self::INVALID_COLOR => 'INVALID_COLOR', 49 | self::OUT_OF_RANGE => 'OUT_OF_RANGE', 50 | ); 51 | 52 | /** 53 | * Maps each constant to a descriptive exception class 54 | * 55 | * @var array 56 | */ 57 | protected static $exception_map = array( 58 | self::GENERAL_ERROR => __NAMESPACE__.'\\exceptions\\general_error', 59 | self::INVALID_CONFIG => __NAMESPACE__.'\\exceptions\\invalid_config', 60 | self::INVALID_VALUE => __NAMESPACE__.'\\exceptions\\invalid_value', 61 | self::INVALID_ARGUMENT => __NAMESPACE__.'\\exceptions\\invalid_argument', 62 | self::INVALID_COLOR => __NAMESPACE__.'\\exceptions\\invalid_color', 63 | self::OUT_OF_RANGE => __NAMESPACE__.'\\exceptions\\out_of_range', 64 | ); 65 | 66 | /** 67 | * Allows the modifying of configuration vars for this class. 68 | * 69 | * @param string $var The variable to modify 70 | * @param bool $value The value to set the variable to 71 | */ 72 | public static function set(string $var, bool $value) { 73 | if (isset(self::$$var)) { 74 | static::$$var = $value; 75 | } 76 | } 77 | 78 | /** 79 | * This function chooses the method to report the error if static::$active is 80 | * equal to TRUE. 81 | * 82 | * @param int $code The error code constant that was passed 83 | * @param string $message The message describing the error 84 | * @return void 85 | */ 86 | public static function trigger(int $code, string $message) { 87 | if (!static::$active) { 88 | return; 89 | } elseif(static::$use_exceptions) { 90 | static::exception($message, $code); 91 | } 92 | static::standard($message, $code); 93 | } 94 | 95 | /** 96 | * Throws an exception with $message 97 | * 98 | * @param string $message The message describing the error 99 | * @return void 100 | */ 101 | protected static function exception(string $message, int $code = 0) { 102 | if (!isset(static::$exception_map[$code])) { 103 | throw new exceptions\general_error('Unknown error type for error: '.$message, $code); 104 | $code = 0; 105 | } 106 | throw new static::$exception_map[$code]($message, $code); 107 | } 108 | 109 | /** 110 | * Triggers a E_USER_WARNING error with $message 111 | * 112 | * @param string $message The message describing the error 113 | * @return void 114 | */ 115 | protected static function standard(string $message, int $code = 0) { 116 | if (!isset(static::$type_map[$code])) { 117 | trigger_error('Unknown error type for error: '.$message); 118 | $code = 0; 119 | } 120 | return trigger_error(sprintf('[%s] %s', static::$type_map[$code], $message), E_USER_WARNING); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/exceptions/general_error.php: -------------------------------------------------------------------------------- 1 | ($r < 128) ? 255 : 0, 24 | 'g' => ($g < 128) ? 255 : 0, 25 | 'b' => ($b < 128) ? 255 : 0 26 | ]; 27 | } 28 | 29 | /** 30 | * Generate the mathematical opposite color for any RGB color 31 | * 32 | * @param int $r The red value 33 | * @param int $g The green value 34 | * @param int $b The blue value 35 | * @return array The mathematical opposite color as an RGB array 36 | */ 37 | public static function rgb_invert(int $r = 0, int $g = 0, int $b = 0) :array { 38 | return [ 39 | 'r' => 255 - $r, 40 | 'g' => 255 - $g, 41 | 'b' => 255 - $b 42 | ]; 43 | } 44 | 45 | /** 46 | * Generate the YIQ score for an RGB color 47 | * 48 | * @param int $r The red value 49 | * @param int $g The green value 50 | * @param int $b The blue value 51 | * @return float The YIQ score 52 | */ 53 | public static function yiq_score(int $r = 0, int $g = 0, int $b = 0) :float { 54 | return (($r * 299) + ($g * 587) + ($b * 114)) / 1000; 55 | } 56 | 57 | /** 58 | * Generate a random RGB color 59 | * 60 | * @param int $min_r The min red to allow 61 | * @param int $max_r The max red to allow 62 | * @param int $min_g The min green to allow 63 | * @param int $max_g The max green to allow 64 | * @param int $min_b The min blue to allow 65 | * @param int $max_b The max blue to allow 66 | * @return array The resulting color as a RGB array 67 | */ 68 | public static function rgb_rand(int $min_r = 0, int $max_r = 255, int $min_g = 0, int $max_g = 255, int $min_b = 0, int $max_b = 255) :array { 69 | return [ 70 | 'r' => rand(abs((int) $min_r) % 256, abs((int) $max_r) % 256), 71 | 'g' => rand(abs((int) $min_g) % 256, abs((int) $max_g) % 256), 72 | 'b' => rand(abs((int) $min_b) % 256, abs((int) $max_b) % 256) 73 | ]; 74 | } 75 | 76 | /** 77 | * Generate a random HSL color 78 | * 79 | * @param int $min_r The min hue to allow 80 | * @param int $max_r The max hue to allow 81 | * @param int $min_g The min saturation to allow 82 | * @param int $max_g The max saturation to allow 83 | * @param int $min_b The min light to allow 84 | * @param int $max_b The max light to allow 85 | * @return array The resulting color as a HSL array 86 | */ 87 | public static function hsl_rand(int $min_h = 0, int $max_h = 359, int $min_s = 0, int $max_s = 100, int $min_l = 0, int $max_l = 100) :array { 88 | return [ 89 | 'h' => rand(abs((int) $min_h) % 360, abs((int) $max_h) % 360), 90 | 's' => rand(abs((int) $min_s) % 101, abs((int) $max_s) % 101), 91 | 'l' => rand(abs((int) $min_l) % 101, abs((int) $max_l) % 101) 92 | ]; 93 | } 94 | 95 | /** 96 | * Blend 2 RGB colors 97 | * 98 | * @param float $r1 The red value from color 1 99 | * @param float $g1 The green value from color 1 100 | * @param float $b1 The blue value from color 1 101 | * @param float $a1 The alpha value from color 1 102 | * @param float $r2 The red value from color 2 103 | * @param float $g2 The green value from color 2 104 | * @param float $b2 The blue value from color 2 105 | * @param float $a2 The alpha value from color 2 106 | * @param float $amount The percentage of color 2 to mix in (defaults to 50 for even blending) 107 | * @return array The resulting color as a RGB array 108 | */ 109 | public static function blend(float $r1, float $g1, float $b1, float $a1, float $r2, float $g2, float $b2, float $a2, float $amount = 50.0) :array { 110 | $x1 = regulate::div(100 - $amount, 100); 111 | $x2 = regulate::div($amount, 100); 112 | return [ 113 | 'r' => round(($r1 * $x1) + ($r2 * $x2), 0), 114 | 'g' => round(($g1 * $x1) + ($g2 * $x2), 0), 115 | 'b' => round(($b1 * $x1) + ($b2 * $x2), 0), 116 | 'a' => ($a1 * $x1) + ($a2 * $x2) 117 | ]; 118 | } 119 | 120 | /** 121 | * Generate a gradient range between 2 RGB colors 122 | * 123 | * @param int $r1 The red value from color 1 124 | * @param int $g1 The green value from color 1 125 | * @param int $b1 The blue value from color 1 126 | * @param int $r2 The red value from color 2 127 | * @param int $g2 The green value from color 2 128 | * @param int $b2 The blue value from color 2 129 | * @param int $steps The size of array to produce, 0 will dynamically 130 | * @return array [TODO] 131 | */ 132 | public static function gradient_range(int $r1 = 0, int $g1 = 0, int $b1 = 0, int $r2 = 0, int $g2 = 0, int $b2 = 0, int $steps = 0) :array { 133 | $diff = [ 134 | 'r' => $r1 - $r2, 135 | 'g' => $g1 - $g2, 136 | 'b' => $b1 - $b2 137 | ]; 138 | $div = max(abs($r1 - $r2), abs($g1 - $g2), abs($b1 - $b2)); 139 | if ($steps != 0) { 140 | $div = abs($steps) - 1; 141 | } 142 | $result = []; 143 | foreach (range(0 , $div) as $i) { 144 | $result[] = [ 145 | 'r' => $r1 + round(regulate::div(-$diff['r'], $div) * $i), 146 | 'g' => $g1 + round(regulate::div(-$diff['g'], $div) * $i), 147 | 'b' => $b1 + round(regulate::div(-$diff['b'], $div) * $i) 148 | ]; 149 | } 150 | return $result; 151 | } 152 | 153 | /** 154 | * Round a RGB input to a 'websafe' color hex 155 | * 156 | * @param int $r The red value 157 | * @param int $g The green value 158 | * @param int $b The blue value 159 | * @return string The resulting color as a hex string 160 | */ 161 | public static function web_safe(int $r = 0, int $g = 0, int $b = 0) :string { 162 | return convert\rgb::to_hex( 163 | round($r / 0x33) * 0x33, 164 | round($g / 0x33) * 0x33, 165 | round($b / 0x33) * 0x33 166 | ); 167 | } 168 | 169 | /** 170 | * Converts a hue to the "Y" spectrum 171 | * 172 | * @param float $hue The hue to convert 173 | * @return float The resulting Y 174 | */ 175 | public static function hue_to_yiq(float $hue) :float { 176 | if ($hue < 60) { 177 | return $hue * 2.5254237288136; 178 | } elseif ($hue < 180) { 179 | return 150 + ($hue - 60) * 4.9243697478992; 180 | } elseif ($hue < 300) { 181 | return 737 + ($hue - 180) * 0.94957983193277; 182 | } 183 | return 851 + ($hue - 300) * 2.5254237288136; 184 | } 185 | 186 | /** 187 | * Converts a "Y" to the hue spectrum 188 | * 189 | * @param float $yiq The "Y" to convert 190 | * @return float The resulting hue 191 | */ 192 | public static function yiq_to_hue(float $yiq) :float { 193 | if ($yiq < 150) { 194 | return $yiq * 0.39597315436242; 195 | } elseif ($yiq < 737) { 196 | return 60 + ($yiq - 150) * 0.20307167235495; 197 | } elseif ($yiq < 851) { 198 | return 180 + ($yiq - 737) * 1.0530973451327; 199 | } 200 | return 300 + ($yiq - 851) * 0.39597315436242; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/hsl.php: -------------------------------------------------------------------------------- 1 | accuracy = $accuracy; 37 | $this->hsl = convert\rgb::to_hsl($rgb_array); 38 | } 39 | 40 | /** 41 | * Shortcut for return the HSL array 42 | * 43 | * @return array The HSL array 44 | */ 45 | public function __invoke() { 46 | return $this->hsl; 47 | } 48 | 49 | /** 50 | * Check if offset exists in data array 51 | * 52 | * @param string $offset The offset to check 53 | * @return bool TRUE if the offset exist, FALSE otherwise 54 | */ 55 | public function offsetExists($offset) :bool { 56 | return isset($this->hsl[$offset]); 57 | } 58 | 59 | /** 60 | * Get an offset if it exists 61 | * 62 | * @param string $offset The offset to get 63 | * @return mixed The value of the offset 64 | */ 65 | public function offsetGet($offset) { 66 | if ($this->offsetExists($offset)) { 67 | return $this->hsl[$offset]; 68 | } 69 | return error::trigger(error::INVALID_ARGUMENT, sprintf( 70 | 'The offset "%s" does not exist in %s', 71 | (string) $offset, 72 | __CLASS__ 73 | )); 74 | } 75 | 76 | /** 77 | * Set a value in the data array 78 | * 79 | * @param string $offset The offset to set 80 | * @param mixed $value The value to set it to 81 | * @return mixed The result 82 | */ 83 | public function offsetSet($offset, $value) { 84 | if ($this->offsetExists($offset)) { 85 | return $this->hsl[$offset] = (float) $value; 86 | } 87 | return error::trigger(error::INVALID_ARGUMENT, sprintf( 88 | 'The offset "%s" cannot be set in %s', 89 | (string) $offset, 90 | __CLASS__ 91 | )); 92 | } 93 | 94 | /** 95 | * Reset an offset to 0 96 | * 97 | * @param string $offset The offset to unset 98 | * @return mixed The result 99 | */ 100 | public function offsetUnset($offset) { 101 | if ($this->offsetExists($offset)) { 102 | return $this->hsl[$offset] = 0.0; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/interfaces/converter.php: -------------------------------------------------------------------------------- 1 | color = clone $this->color; 20 | $this->cache = clone $this->cache; 21 | } 22 | 23 | /** 24 | * Custom serialize function 25 | * 26 | * @return string This instance serialized as an RGB string 27 | */ 28 | public function serialize() :string { 29 | return $this->color->serialize(); 30 | } 31 | 32 | /** 33 | * Custom unserialize function 34 | * 35 | * @param string $serialized This instance serialized as an RGB string 36 | * @return void 37 | */ 38 | public function unserialize($serialized) { 39 | $unserialized = (array) json_decode((string) $serialized); 40 | regulate::rgb_array($unserialized); 41 | $this->set($unserialized, 'rgb'); 42 | } 43 | 44 | /** 45 | * Custom JSON serialize function 46 | * 47 | * @return string This instance serialized as an JSON RGB string 48 | */ 49 | public function jsonSerialize() :array { 50 | return $this->color->jsonSerialize(); 51 | } 52 | 53 | protected function get_scheme(string $scheme_name, string $return_type = 'hex', $scheme_class) :array { 54 | if (!is_null($cached = $this->cache->get(get_class($scheme_class).'_'.$scheme_name.'_'.$return_type, $this->hex()))) { 55 | return $cached; 56 | } 57 | $result = static::_scheme($scheme_name, [$scheme_class, strtolower($return_type)], $this->hsl(3)); 58 | $this->cache->set(get_class($scheme_class).'_'.$scheme_name.'_'.$return_type, $this->hex(), $result); 59 | return $result; 60 | } 61 | 62 | /** 63 | * Handles scheme generator callbacks 64 | * 65 | * @param string $scheme_name The name of the scheme algorithm to use 66 | * @param string $callback The return type callback 67 | * @param array $hsl The base color as an HSL array 68 | * @return array The resulting scheme in the proper format, OR an empty array on failure. 69 | */ 70 | protected static function _scheme(string $scheme_name, array $callback, array $hsl) :array { 71 | if (is_callable($callback)) { 72 | return call_user_func($callback, $hsl['h'], $hsl['s'], $hsl['l'], $scheme_name); 73 | } 74 | error::trigger(error::INVALID_ARGUMENT, sprintf( 75 | 'The $callback "%s" is not a valid callback', 76 | print_r($callback, 1), 77 | __CLASS__, 78 | __FUNCTION__ 79 | )); 80 | return []; 81 | } 82 | 83 | /** 84 | * Set whether or not caching should be active. 85 | * 86 | * @param bool $active If TRUE caching is turned on, otherwise cashing is turned off. 87 | * @return void 88 | */ 89 | public function cache(bool $active = TRUE) { 90 | $this->cache->active = $active; 91 | } 92 | 93 | /** 94 | * Reset the cache for this instance 95 | * 96 | * @return void 97 | */ 98 | public function reset_cache() { 99 | $this->cache->reset(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/modify.php: -------------------------------------------------------------------------------- 1 | rgb); 19 | $scope = strtolower($scope); 20 | $adjustment = max(min($adjustment, 255), 0 - 255); // Force valid range 21 | $adjustment = static::_convert_to_exact($adjustment, 255, $as_percentage); 22 | $current[$scope] = static::_convert_to_abs($current[$scope], $adjustment, $set_absolute, 0, 255); 23 | return static::regenerate_rgb($color, $current, $scope); 24 | } 25 | 26 | public static function hsl(color $color, string $scope, float $adjustment, bool $as_percentage, bool $set_absolute) { 27 | $current = array_combine(['hue', 'saturation', 'light'], $color->hsl()); 28 | $scope = strtolower($scope); 29 | $max = 100; 30 | if ($scope == 'hue') { 31 | $max = 359; 32 | } 33 | $adjustment = max(min($adjustment, $max), 0 - $max); // Force valid range 34 | $adjustment = static::_convert_to_exact($adjustment, $max, $as_percentage); 35 | $current[$scope] = static::_convert_to_abs($current[$scope], $adjustment, $set_absolute, 0, $max); 36 | return static::regenerate_hsl($color, $current, $scope); 37 | } 38 | 39 | protected static function _convert_to_exact(float $adjustment, float $max, bool $as_percentage) { 40 | if ($as_percentage) { 41 | return ($adjustment / 100) * abs($max); 42 | } 43 | return $adjustment; 44 | } 45 | 46 | protected static function _convert_to_abs(float $current, float $adjustment, bool $set_absolute, float $min = 0, float $max = PHP_INT_MAX) { 47 | if ($set_absolute) { 48 | return abs($adjustment); 49 | } 50 | return max(min($current + $adjustment, $max), $min); 51 | } 52 | 53 | protected static function regenerate_rgb(color $color, array $update, string $return_offset = '') { 54 | $color->import_rgb([ 55 | 'r' => $update['red'], 56 | 'g' => $update['green'], 57 | 'b' => $update['blue'] 58 | ]); 59 | if (isset($update[$return_offset])) { 60 | return $update[$return_offset]; 61 | } 62 | } 63 | 64 | protected static function regenerate_hsl(color $color, array $update, string $return_offset = '') { 65 | $color->import_hsl([ 66 | 'h' => $update['hue'], 67 | 's' => $update['saturation'], 68 | 'l' => $update['light'] 69 | ]); 70 | if (isset($update[$return_offset])) { 71 | return $update[$return_offset]; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/regulate.php: -------------------------------------------------------------------------------- 1 | 000000) 166 | * 167 | * @param string &$hex_str The hex string to modify 168 | * @return void 169 | */ 170 | public static function _expand_shorthand(string &$hex_str) { 171 | if (strlen($hex_str) === 3) { 172 | $r = $hex_str[0]; 173 | $g = $hex_str[1]; 174 | $b = $hex_str[2]; 175 | $hex_str = $r.$r.$g.$g.$b.$b; 176 | } 177 | } 178 | 179 | /** 180 | * Verify that the hex string is actually a hex string. If not force it to 181 | * '000000' 182 | * 183 | * @param string &$hex_str The hex string to modify 184 | * @return void 185 | */ 186 | public static function _validate_hex_str(string &$hex_str, bool $check_only = FALSE) :bool { 187 | if (preg_match('/\A#?(?:[0-9a-f]{3}|[0-9a-f]{6})\Z/i', $hex_str)) { 188 | return TRUE; 189 | } 190 | if (!$check_only) { 191 | error::trigger(error::INVALID_ARGUMENT, sprintf( 192 | 'The input of %s::%s() was not a valid hex string, forcing value to 000000', 193 | __CLASS__, 194 | __FUNCTION__ 195 | )); 196 | $hex_str = '000000'; 197 | } 198 | return FALSE; 199 | } 200 | 201 | /** 202 | * Force an array to have specific lower-case keys. If the array is an indexed 203 | * array and the keys are provided, convert it to an associative array. 204 | * 205 | * @param array &$array The array to be modified 206 | * @return void 207 | */ 208 | public static function standardize_array(array &$array, array $keys = []) { 209 | if (!empty($keys) && array_keys($array) === range(0, count($array) - 1) && count($array) == count($keys)) { 210 | $array = array_combine($keys, $array); 211 | } else { 212 | $array = array_change_key_case($array) + array_fill_keys($keys, 0); 213 | } 214 | } 215 | 216 | /** 217 | * Absolute and divide any number so it fits between 0 and $max 218 | * 219 | * @param float $number The original number 220 | * @param float $max The maximum value $number should be 221 | * @return float The resulting number as a float 222 | */ 223 | public static function max(float $number, float $max) :float { 224 | $max = abs($max); 225 | if ($number > $max) { 226 | $number -= floor($number / ($max + 1)) * ($max + 1); 227 | } 228 | return $number; 229 | } 230 | 231 | /** 232 | * Simple dividing method to handle division by 0 233 | * 234 | * @param float $number The number to divide 235 | * @param float $divisor The number to divide by 236 | * @return float The result 237 | */ 238 | public static function div(float $number, float $divisor) :float { 239 | if ($divisor == 0) { 240 | return 0; 241 | } 242 | return $number / $divisor; 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/traits/converter.php: -------------------------------------------------------------------------------- 1 | = $min && $value <= $max); 81 | } 82 | 83 | public static function in_between(float $value, float $min, float $max) :bool { 84 | return ($value > $min && $value < $max); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/yiq_scheme.php: -------------------------------------------------------------------------------- 1 | &$hsl) { 189 | if ($i == 0) { 190 | $org = $hsl['h']; 191 | continue; 192 | } 193 | $hsl['h'] = static::yiq_adjust($org, $hsl['h'] - $org); 194 | } 195 | 196 | return $scheme; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /tasks.todo: -------------------------------------------------------------------------------- 1 | General: 2 | ☐ Add git flow 3 | ☐ Add contact form 4 | Class Specific: 5 | ☐ Add main::difference() for comparing 2 different colors 6 | ☐ css/main should support importing css rgb/hsl percentage values 7 | Bugs: 8 | Minor: 9 | Documentation: 10 | ☐ Add code docs to class 'modify' 11 | ☐ Add readme.md for github license tag 12 | Testing: 13 | ☐ Add test for class 'main' 14 | ☐ Add randomized testing for scheme generation 15 | ☐ Test against float vs int function arguments 16 | ☐ Test for cloning issues 17 | 18 | ___________________ 19 | Archive: 20 | ✔ Modify main attribute methods return either existing or resulting value @done (16-10-21 14:54) @project(General) 21 | ✔ Make main::alpha() a modification method @done (16-10-21 14:54) @project(General) 22 | ✔ Add PHP 5 support @done (16-10-21 14:54) @project(General) 23 | ✔ Add test for class 'color' @done (16-09-30 10:09) @project(Testing) 24 | ✔ Validate scope in modify::rgb() and modify::hsl @done (16-09-29 16:53) @project(Class Specific) 25 | ✔ Add test for class 'scheme' @done (16-09-24 13:35) @project(Testing) 26 | ✔ Add test for class 'regulate' @done (16-09-24 13:35) @project(Testing) 27 | ✔ Add test for class 'hsl' @done (16-09-24 13:35) @project(Testing) 28 | ✔ Add test for class 'error' @done (16-09-24 13:35) @project(Testing) 29 | ✔ Add code docs to class 'hsl' @done (16-09-24 13:35) @project(Documentation) 30 | ✔ Add code docs to class 'generate' @done (16-09-24 13:35) @project(Documentation) 31 | ✔ add main::rgb_rand() and main::hsl_rand() @done (16-09-24 13:34) @project(Class Specific) 32 | ✔ Create README file @done (16-09-24 13:34) @project(Documentation) 33 | ✔ Add code docs to class 'main' @done (16-09-24 13:34) @project(Documentation) 34 | ✔ Add cache class @done (16-09-24 13:33) @project(General) 35 | ✔ Add ability to generate all colors within the selected color range, with steps settable @done (16-09-24 13:33) @project(General) 36 | ✔ replace main::*_scheme() with main::scheme($name, $return_type = 'hex') @done (16-08-09 17:19) @project(Class Specific) 37 | ✔ Abstract main class serialize methods @done (16-08-09 17:19) @project(Class Specific) 38 | ✔ Add mixing function @done (16-08-08 11:34) @project(General) 39 | ✔ Add hsb support @done (16-08-08 11:32) @project(General) 40 | ✔ Add JSON serialization support @done (16-08-01 18:34) @project(General) 41 | ✔ Fix scheme::is_dark() docs (return is void) @done (16-07-22 15:45) @project(Minor) 42 | ✔ Fix color::_get_array_type() docs ($color should be type array) @done (16-07-22 15:44) @project(Minor) 43 | ✔ scheme::is_dark() should force $is_dark to be boolean @done (16-07-22 15:43) @project(Bugs) 44 | ✔ Add test for class 'check' @done (16-07-22 14:29) @project(Testing) 45 | ✔ Alias main::*_scheme() to 'scheme' class @done (16-07-21 18:18) @project(Class Specific) 46 | ✔ Implement alpha channel support @done (16-07-21 16:14) @project(General) 47 | ✔ Implement exporting as CSS values @done (16-07-20 18:03) @project(General) 48 | ✔ Add meta folder for generating samples @done (16-07-20 16:17) @project(General) 49 | -------------------------------------------------------------------------------- /testing/bootstrap.php: -------------------------------------------------------------------------------- 1 | vars = [ 28 | 'conversions' => [ 29 | // The 8 basic colors of the RGB spectrum with their conversions 30 | '000000' => [ 31 | 'int' => 0x000000, 32 | 'hex' => '000000', 33 | 'rgb' => ['r' => 0, 'g' => 0, 'b' => 0 ], 34 | 'hsl' => ['h' => 0, 's' => 0, 'l' => 0], 35 | 'hsb' => ['h' => 0, 's' => 0, 'b' => 0], 36 | 'cmyk' => ['c' => 0, 'm' => 0, 'y' => 0, 'k' => 100] 37 | ], 38 | 'FFFFFF' => [ 39 | 'int' => 0xFFFFFF, 40 | 'hex' => 'FFFFFF', 41 | 'rgb' => ['r' => 255, 'g' => 255, 'b' => 255], 42 | 'hsl' => ['h' => 0, 's' => 0, 'l' => 100], 43 | 'hsb' => ['h' => 0, 's' => 0, 'b' => 100], 44 | 'cmyk' => ['c' => 0, 'm' => 0, 'y' => 0, 'k' => 0] 45 | ], 46 | 'FFFF00' => [ 47 | 'int' => 0xFFFF00, 48 | 'hex' => 'FFFF00', 49 | 'rgb' => ['r' => 255, 'g' => 255, 'b' => 0 ], 50 | 'hsl' => ['h' => 60, 's' => 100, 'l' => 50], 51 | 'hsb' => ['h' => 60, 's' => 100, 'b' => 100], 52 | 'cmyk' => ['c' => 0, 'm' => 0, 'y' => 100, 'k' => 0] 53 | ], 54 | 'FF00FF' => [ 55 | 'int' => 0xFF00FF, 56 | 'hex' => 'FF00FF', 57 | 'rgb' => ['r' => 255, 'g' => 0, 'b' => 255], 58 | 'hsl' => ['h' => 300, 's' => 100, 'l' => 50], 59 | 'hsb' => ['h' => 300, 's' => 100, 'b' => 100], 60 | 'cmyk' => ['c' => 0, 'm' => 100, 'y' => 0, 'k' => 0] 61 | ], 62 | 'FF0000' => [ 63 | 'int' => 0xFF0000, 64 | 'hex' => 'FF0000', 65 | 'rgb' => ['r' => 255, 'g' => 0, 'b' => 0 ], 66 | 'hsl' => ['h' => 0, 's' => 100, 'l' => 50], 67 | 'hsb' => ['h' => 0, 's' => 100, 'b' => 100], 68 | 'cmyk' => ['c' => 0, 'm' => 100, 'y' => 100, 'k' => 0] 69 | ], 70 | '00FFFF' => [ 71 | 'int' => 0x00FFFF, 72 | 'hex' => '00FFFF', 73 | 'rgb' => ['r' => 0, 'g' => 255, 'b' => 255], 74 | 'hsl' => ['h' => 180, 's' => 100, 'l' => 50], 75 | 'hsb' => ['h' => 180, 's' => 100, 'b' => 100], 76 | 'cmyk' => ['c' => 100, 'm' => 0, 'y' => 0, 'k' => 0] 77 | ], 78 | '00FF00' => [ 79 | 'int' => 0x00FF00, 80 | 'hex' => '00FF00', 81 | 'rgb' => ['r' => 0, 'g' => 255, 'b' => 0 ], 82 | 'hsl' => ['h' => 120, 's' => 100, 'l' => 50], 83 | 'hsb' => ['h' => 120, 's' => 100, 'b' => 100], 84 | 'cmyk' => ['c' => 100, 'm' => 0, 'y' => 100, 'k' => 0] 85 | ], 86 | '0000FF' => [ 87 | 'int' => 0x0000FF, 88 | 'hex' => '0000FF', 89 | 'rgb' => ['r' => 0, 'g' => 0, 'b' => 255], 90 | 'hsl' => ['h' => 240, 's' => 100, 'l' => 50], 91 | 'hsb' => ['h' => 240, 's' => 100, 'b' => 100], 92 | 'cmyk' => ['c' => 100, 'm' => 100, 'y' => 0, 'k' => 0] 93 | ] 94 | ] 95 | ]; 96 | } 97 | 98 | /** 99 | * 100 | */ 101 | public function tearDown() { 102 | 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /testing/tests/00_ErrorTest.php: -------------------------------------------------------------------------------- 1 | vars['conversions'] as $hex => $conv) { 16 | $this->assertEquals(convert::hex_to_rgb($hex), $conv['rgb']); 17 | } 18 | } 19 | 20 | /** 21 | * @test 22 | */ 23 | public function RGB_To_HEX() { 24 | foreach ($this->vars['conversions'] as $hex => $conv) { 25 | $this->assertEquals(convert::rgb_to_hex($conv['rgb']['r'], $conv['rgb']['g'], $conv['rgb']['b']), $hex); 26 | } 27 | } 28 | 29 | /** 30 | * @test 31 | */ 32 | public function RGB_To_CMYK() { 33 | foreach ($this->vars['conversions'] as $conv) { 34 | $this->assertEquals(convert::rgb_to_cmyk($conv['rgb']['r'], $conv['rgb']['g'], $conv['rgb']['b']), $conv['cmyk']); 35 | } 36 | } 37 | 38 | /** 39 | * @test 40 | */ 41 | public function CMYK_To_RGB() { 42 | foreach ($this->vars['conversions'] as $conv) { 43 | $this->assertEquals(convert::cmyk_to_rgb($conv['cmyk']['c'], $conv['cmyk']['m'], $conv['cmyk']['y'], $conv['cmyk']['k']), $conv['rgb']); 44 | } 45 | } 46 | 47 | /** 48 | * @test 49 | */ 50 | public function RGB_To_HSL() { 51 | foreach ($this->vars['conversions'] as $conv) { 52 | $this->assertEquals(convert::rgb_to_hsl($conv['rgb']['r'], $conv['rgb']['g'], $conv['rgb']['b']), $conv['hsl']); 53 | } 54 | } 55 | 56 | /** 57 | * @test 58 | */ 59 | public function HSL_To_RGB() { 60 | foreach ($this->vars['conversions'] as $conv) { 61 | $this->assertEquals(convert::hsl_to_rgb($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), $conv['rgb']); 62 | } 63 | } 64 | 65 | /** 66 | * @test 67 | */ 68 | public function RGB_To_HSB() { 69 | foreach ($this->vars['conversions'] as $conv) { 70 | $this->assertEquals(convert::rgb_to_hsb($conv['rgb']['r'], $conv['rgb']['g'], $conv['rgb']['b']), $conv['hsb']); 71 | } 72 | } 73 | 74 | /** 75 | * @test 76 | */ 77 | public function HSB_To_RGB() { 78 | foreach ($this->vars['conversions'] as $conv) { 79 | $this->assertEquals(convert::hsb_to_rgb($conv['hsb']['h'], $conv['hsb']['s'], $conv['hsb']['b']), $conv['rgb']); 80 | } 81 | } 82 | 83 | /** 84 | * Testing for mathematical drifts when converting between color spaces. 85 | * 86 | * NOTE: This is not a full color space test, it only skims the RGB color 87 | * space for differences. 88 | * 89 | * @ignored_test 90 | */ 91 | public function RGB_HSL_Interlace_Color_Drift() { 92 | foreach (range(0 ,51) as $b) { 93 | foreach (range(0 ,51) as $g) { 94 | foreach (range(0 ,51) as $r) { 95 | $rgb1 = ['r' => $r * 5, 'g' => $g * 5, 'b' => $b * 5]; 96 | $hsl1 = convert::rgb_to_hsl($rgb1['r'], $rgb1['g'],$rgb1['b']); 97 | $rgb2 = convert::hsl_to_rgb($hsl1['h'], $hsl1['s'],$hsl1['l']); 98 | $hsl2 = convert::rgb_to_hsl($rgb2['r'], $rgb2['g'],$rgb2['b']); 99 | if (!empty(array_diff_assoc($rgb1, $rgb2)) || !empty(array_diff_assoc($hsl1, $hsl2))) { 100 | $this->assertEmpty(array_diff_assoc($rgb1, $rgb2), sprintf( 101 | 'RGB color drift detected: rgb1(%s, %s, %s) != rgb2(%s, %s, %s)', 102 | $rgb1['r'], 103 | $rgb1['g'], 104 | $rgb1['b'], 105 | $rgb2['r'], 106 | $rgb2['g'], 107 | $rgb2['b'] 108 | )); 109 | $this->assertEmpty(array_diff_assoc($hsl1, $hsl2), sprintf( 110 | 'HSL color drift detected: hsl1(%s, %s, %s) != hsl2(%s, %s, %s)', 111 | $hsl1['r'], 112 | $hsl1['g'], 113 | $hsl1['b'], 114 | $hsl2['r'], 115 | $hsl2['g'], 116 | $hsl2['b'] 117 | )); 118 | } else { 119 | $this->assertEmpty(array_diff_assoc($rgb1, $rgb2)); 120 | $this->assertEmpty(array_diff_assoc($hsl1, $hsl2)); 121 | } 122 | } 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /testing/tests/03_GeneratorTest.php: -------------------------------------------------------------------------------- 1 | vars['conversions']; 16 | $this->assertEquals(generate::rgb_contrast($conv['000000']['rgb']['r'], $conv['000000']['rgb']['g'], $conv['000000']['rgb']['b']), $conv['FFFFFF']['rgb']); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function RGB_Invert() { 23 | $conv = $this->vars['conversions']; 24 | $this->assertEquals(generate::rgb_invert($conv['000000']['rgb']['r'], $conv['000000']['rgb']['g'], $conv['000000']['rgb']['b']), $conv['FFFFFF']['rgb']); 25 | } 26 | 27 | /** 28 | * @test 29 | */ 30 | public function YIQ_Score() { 31 | $this->assertEquals(generate::yiq_score(255, 255, 255), 255); 32 | $this->assertEquals(generate::yiq_score(0, 0, 0), 0); 33 | } 34 | 35 | /** 36 | * @test 37 | */ 38 | public function RGB_Random() { 39 | foreach (range(1, 1000) as $i) { 40 | $rgb = generate::rgb_rand(); 41 | $this->assertTrue($rgb['r'] >= 0 && $rgb['r'] <= 255); 42 | $this->assertTrue($rgb['g'] >= 0 && $rgb['g'] <= 255); 43 | $this->assertTrue($rgb['b'] >= 0 && $rgb['b'] <= 255); 44 | } 45 | } 46 | 47 | /** 48 | * @test 49 | */ 50 | public function HSL_Random() { 51 | foreach (range(1, 1000) as $i) { 52 | $hsl = generate::hsl_rand(); 53 | $this->assertTrue($hsl['h'] >= 0 && $hsl['h'] <= 359); 54 | $this->assertTrue($hsl['s'] >= 0 && $hsl['s'] <= 100); 55 | $this->assertTrue($hsl['l'] >= 0 && $hsl['l'] <= 100); 56 | } 57 | } 58 | 59 | /** 60 | * @test 61 | */ 62 | public function Blend() { 63 | $rgb1 = $this->vars['conversions']['FFFFFF']['rgb'] + ['a' => 100]; 64 | $rgb2 = $this->vars['conversions']['000000']['rgb'] + ['a' => 100]; 65 | $rgb3 = generate::blend($rgb1['r'], $rgb1['g'], $rgb1['b'], $rgb1['a'], $rgb2['r'], $rgb2['g'], $rgb2['b'], $rgb2['a']); 66 | $this->assertEquals(['r' => 128, 'g' => 128, 'b' => 128, 'a' => 100], $rgb3); 67 | 68 | $rgb1 = $this->vars['conversions']['FFFFFF']['rgb'] + ['a' => 100]; 69 | $rgb2 = $this->vars['conversions']['000000']['rgb'] + ['a' => 50]; 70 | $rgb3 = generate::blend($rgb1['r'], $rgb1['g'], $rgb1['b'], $rgb1['a'], $rgb2['r'], $rgb2['g'], $rgb2['b'], $rgb2['a'], 25); 71 | $this->assertEquals(['r' => 191, 'g' => 191, 'b' => 191, 'a' => 87.5], $rgb3); 72 | } 73 | 74 | /** 75 | * @test 76 | */ 77 | public function Web_Safe() { 78 | foreach (range(1, 1000) as $i) { 79 | $rgb = generate::rgb_rand(); 80 | $web = generate::web_safe($rgb['r'], $rgb['g'], $rgb['b']); 81 | foreach (convert::hex_to_rgb($web) as $val) { 82 | $this->assertTrue(is_int($val / 0x33)); 83 | } 84 | } 85 | } 86 | 87 | /** 88 | * @test 89 | */ 90 | public function Hue_To_YQI() { 91 | $this->assertEquals(0, generate::hue_to_yiq(0)); 92 | $this->assertEquals(63.135593220338983, generate::hue_to_yiq(25)); 93 | $this->assertEquals(149, generate::hue_to_yiq(59)); 94 | $this->assertEquals(150, generate::hue_to_yiq(60)); 95 | $this->assertEquals(445.46218487394958, generate::hue_to_yiq(120)); 96 | $this->assertEquals(736, generate::hue_to_yiq(179)); 97 | $this->assertEquals(737, generate::hue_to_yiq(180)); 98 | $this->assertEquals(755.99159663865544, generate::hue_to_yiq(200)); 99 | $this->assertEquals(850, generate::hue_to_yiq(299)); 100 | $this->assertEquals(851, generate::hue_to_yiq(300)); 101 | $this->assertEquals(926.76271186440681, generate::hue_to_yiq(330)); 102 | $this->assertEquals(1000, generate::hue_to_yiq(359)); 103 | } 104 | 105 | /** 106 | * @test 107 | */ 108 | public function YQI_To_Hue() { 109 | $this->assertEquals(0, generate::yiq_to_hue(0)); 110 | $this->assertEquals(39.597315436241608, generate::yiq_to_hue(100)); 111 | $this->assertEquals(59, generate::yiq_to_hue(149)); 112 | $this->assertEquals(60, generate::yiq_to_hue(150)); 113 | $this->assertEquals(120.92150170648463, generate::yiq_to_hue(450)); 114 | $this->assertEquals(179, generate::yiq_to_hue(736)); 115 | $this->assertEquals(180, generate::yiq_to_hue(737)); 116 | $this->assertEquals(235.81415929203541, generate::yiq_to_hue(790)); 117 | $this->assertEquals(299, generate::yiq_to_hue(850)); 118 | $this->assertEquals(300, generate::yiq_to_hue(851)); 119 | $this->assertEquals(331.28187919463085, generate::yiq_to_hue(930)); 120 | $this->assertEquals(359, generate::yiq_to_hue(1000)); 121 | } 122 | 123 | /** 124 | * @test 125 | */ 126 | public function Gradient() { 127 | // count down 128 | $test1 = generate::gradient_range(2, 0, 0, 0, 0, 0); 129 | $this->assertEquals([ 130 | ['r' => 2, 'g' => 0, 'b' => 0], 131 | ['r' => 1, 'g' => 0, 'b' => 0], 132 | ['r' => 0, 'g' => 0, 'b' => 0] 133 | ], $test1); 134 | // count up 135 | $test2 = generate::gradient_range(0, 0, 0, 2, 0, 0); 136 | $this->assertEquals([ 137 | ['r' => 0, 'g' => 0, 'b' => 0], 138 | ['r' => 1, 'g' => 0, 'b' => 0], 139 | ['r' => 2, 'g' => 0, 'b' => 0] 140 | ], $test2); 141 | // count up and down 142 | $test3 = generate::gradient_range(5, 0, 3, 0, 5, 3); 143 | $this->assertEquals([ 144 | ['r' => 5, 'g' => 0, 'b' => 3], 145 | ['r' => 4, 'g' => 1, 'b' => 3], 146 | ['r' => 3, 'g' => 2, 'b' => 3], 147 | ['r' => 2, 'g' => 3, 'b' => 3], 148 | ['r' => 1, 'g' => 4, 'b' => 3], 149 | ['r' => 0, 'g' => 5, 'b' => 3] 150 | ], $test3); 151 | // 1 color 152 | $test4 = generate::gradient_range(5, 5, 5, 5, 5, 5); 153 | $this->assertEquals([ 154 | ['r' => 5, 'g' => 5, 'b' => 5] 155 | ], $test4); 156 | // stretch 157 | $test5 = generate::gradient_range(5, 0, 3, 0, 5, 3, 12); 158 | $this->assertEquals([ 159 | ['r' => 5, 'g' => 0, 'b' => 3], 160 | ['r' => 5, 'g' => 0, 'b' => 3], 161 | ['r' => 4, 'g' => 1, 'b' => 3], 162 | ['r' => 4, 'g' => 1, 'b' => 3], 163 | ['r' => 3, 'g' => 2, 'b' => 3], 164 | ['r' => 3, 'g' => 2, 'b' => 3], 165 | ['r' => 2, 'g' => 3, 'b' => 3], 166 | ['r' => 2, 'g' => 3, 'b' => 3], 167 | ['r' => 1, 'g' => 4, 'b' => 3], 168 | ['r' => 1, 'g' => 4, 'b' => 3], 169 | ['r' => 0, 'g' => 5, 'b' => 3], 170 | ['r' => 0, 'g' => 5, 'b' => 3] 171 | ], $test5); 172 | // stretch 1 color 173 | $test4 = generate::gradient_range(5, 5, 5, 5, 5, 5, 5); 174 | $this->assertEquals([ 175 | ['r' => 5, 'g' => 5, 'b' => 5], 176 | ['r' => 5, 'g' => 5, 'b' => 5], 177 | ['r' => 5, 'g' => 5, 'b' => 5], 178 | ['r' => 5, 'g' => 5, 'b' => 5], 179 | ['r' => 5, 'g' => 5, 'b' => 5] 180 | ], $test4); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /testing/tests/04_CheckTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(check::is_dark(0, 0, 0)); 17 | // White 18 | $this->assertFalse(check::is_dark(255, 255, 255)); 19 | // Gray (mathematical dark) 20 | $this->assertTrue(check::is_dark(127, 127, 127)); 21 | // Gray (mathematical light) 22 | $this->assertFalse(check::is_dark(128, 128, 128)); 23 | } 24 | 25 | /** 26 | * @test 27 | */ 28 | public function RGB_Contrast() { 29 | $possible_contrasts = [11,30,41,59,70,89,100]; 30 | foreach ($this->vars['conversions'] as $hex1 => $color1) { 31 | foreach ($this->vars['conversions'] as $hex2 => $color2) { 32 | if ($hex1 == $hex2) { 33 | $this->assertEquals(0, check::rgb_contrast($color1['rgb'], $color2['rgb'])); 34 | } else { 35 | $this->assertTrue(in_array(round(check::rgb_contrast($color1['rgb'], $color2['rgb'])), $possible_contrasts)); 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /testing/tests/05_SchemeTest.php: -------------------------------------------------------------------------------- 1 | vars['conversions'] as $hex => $conv) { 16 | $schemes = [ 17 | scheme::analogous_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 18 | scheme::analogous_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 19 | scheme::analogous_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 20 | ]; 21 | foreach ($schemes as $scheme) { 22 | $this->assertEquals(5, count($scheme)); 23 | $this->assertEquals($scheme[0], $conv['hsl']); 24 | foreach ($scheme as $key => $color) { 25 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 26 | $diff = $color; 27 | regulate::hsl_array($color); 28 | $this->assertEquals($diff, $color); 29 | } 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * @test 36 | */ 37 | public function Complementary_Set() { 38 | foreach ($this->vars['conversions'] as $hex => $conv) { 39 | $schemes = [ 40 | scheme::complementary_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 41 | scheme::complementary_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 42 | scheme::complementary_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 43 | ]; 44 | foreach ($schemes as $scheme) { 45 | $this->assertEquals(5, count($scheme)); 46 | $this->assertEquals($scheme[0], $conv['hsl']); 47 | foreach ($scheme as $key => $color) { 48 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 49 | $diff = $color; 50 | regulate::hsl_array($color); 51 | $this->assertEquals($diff, $color); 52 | } 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * @test 59 | */ 60 | public function Compound_Set() { 61 | foreach ($this->vars['conversions'] as $hex => $conv) { 62 | $schemes = [ 63 | scheme::compound_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 64 | scheme::compound_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 65 | scheme::compound_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 66 | ]; 67 | foreach ($schemes as $scheme) { 68 | $this->assertEquals(5, count($scheme)); 69 | $this->assertEquals($scheme[0], $conv['hsl']); 70 | foreach ($scheme as $key => $color) { 71 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 72 | $diff = $color; 73 | regulate::hsl_array($color); 74 | $this->assertEquals($diff, $color); 75 | } 76 | } 77 | } 78 | } 79 | 80 | /** 81 | * @test 82 | */ 83 | public function Monochromatic_Set() { 84 | foreach ($this->vars['conversions'] as $hex => $conv) { 85 | $schemes = [ 86 | scheme::monochromatic_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 87 | scheme::monochromatic_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 88 | scheme::monochromatic_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 89 | ]; 90 | foreach ($schemes as $scheme) { 91 | $this->assertEquals(5, count($scheme)); 92 | $this->assertEquals($scheme[0], $conv['hsl']); 93 | foreach ($scheme as $key => $color) { 94 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 95 | $diff = $color; 96 | regulate::hsl_array($color); 97 | $this->assertEquals($diff, $color); 98 | } 99 | } 100 | } 101 | } 102 | 103 | /** 104 | * @test 105 | */ 106 | public function Shades_Set() { 107 | foreach ($this->vars['conversions'] as $hex => $conv) { 108 | $schemes = [ 109 | scheme::shades_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 110 | scheme::shades_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 111 | scheme::shades_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 112 | ]; 113 | foreach ($schemes as $scheme) { 114 | $this->assertEquals(5, count($scheme)); 115 | $this->assertEquals($scheme[0], $conv['hsl']); 116 | foreach ($scheme as $key => $color) { 117 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 118 | $diff = $color; 119 | regulate::hsl_array($color); 120 | $this->assertEquals($diff, $color); 121 | } 122 | } 123 | } 124 | } 125 | 126 | /** 127 | * @test 128 | */ 129 | public function Tetrad_Set() { 130 | foreach ($this->vars['conversions'] as $hex => $conv) { 131 | $schemes = [ 132 | scheme::tetrad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 133 | scheme::tetrad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 134 | scheme::tetrad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 135 | ]; 136 | foreach ($schemes as $scheme) { 137 | $this->assertEquals(5, count($scheme)); 138 | $this->assertEquals($scheme[0], $conv['hsl']); 139 | foreach ($scheme as $key => $color) { 140 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 141 | $diff = $color; 142 | regulate::hsl_array($color); 143 | $this->assertEquals($diff, $color); 144 | } 145 | } 146 | } 147 | } 148 | 149 | /** 150 | * @test 151 | */ 152 | public function Weighted_Tetrad_Set() { 153 | foreach ($this->vars['conversions'] as $hex => $conv) { 154 | $schemes = [ 155 | scheme::weighted_tetrad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 156 | scheme::weighted_tetrad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 157 | scheme::weighted_tetrad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 158 | ]; 159 | foreach ($schemes as $scheme) { 160 | $this->assertEquals(5, count($scheme)); 161 | $this->assertEquals($scheme[0], $conv['hsl']); 162 | foreach ($scheme as $key => $color) { 163 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 164 | $diff = $color; 165 | regulate::hsl_array($color); 166 | $this->assertEquals($diff, $color); 167 | } 168 | } 169 | } 170 | } 171 | 172 | /** 173 | * @test 174 | */ 175 | public function Triad_Set() { 176 | foreach ($this->vars['conversions'] as $hex => $conv) { 177 | $schemes = [ 178 | scheme::triad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 179 | scheme::triad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 180 | scheme::triad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 181 | ]; 182 | foreach ($schemes as $scheme) { 183 | $this->assertEquals(5, count($scheme)); 184 | $this->assertEquals($scheme[0], $conv['hsl']); 185 | foreach ($scheme as $key => $color) { 186 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 187 | $diff = $color; 188 | regulate::hsl_array($color); 189 | $this->assertEquals($diff, $color); 190 | } 191 | } 192 | } 193 | } 194 | 195 | /** 196 | * @test 197 | */ 198 | public function Weighted_Triad_Set() { 199 | foreach ($this->vars['conversions'] as $hex => $conv) { 200 | $schemes = [ 201 | scheme::weighted_triad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 202 | scheme::weighted_triad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 203 | scheme::weighted_triad_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 204 | ]; 205 | foreach ($schemes as $scheme) { 206 | $this->assertEquals(5, count($scheme)); 207 | $this->assertEquals($scheme[0], $conv['hsl']); 208 | foreach ($scheme as $key => $color) { 209 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 210 | $diff = $color; 211 | regulate::hsl_array($color); 212 | $this->assertEquals($diff, $color); 213 | } 214 | } 215 | } 216 | } 217 | 218 | /** 219 | * @test 220 | */ 221 | public function Rectangular_Set() { 222 | foreach ($this->vars['conversions'] as $hex => $conv) { 223 | $schemes = [ 224 | scheme::rectangular_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l']), 225 | scheme::rectangular_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], TRUE), 226 | scheme::rectangular_set($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], FALSE) 227 | ]; 228 | foreach ($schemes as $scheme) { 229 | $this->assertEquals(5, count($scheme)); 230 | $this->assertEquals($scheme[0], $conv['hsl']); 231 | foreach ($scheme as $key => $color) { 232 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 233 | $diff = $color; 234 | regulate::hsl_array($color); 235 | $this->assertEquals($diff, $color); 236 | } 237 | } 238 | } 239 | } 240 | 241 | /** 242 | * @test 243 | */ 244 | public function ReturnRGB() { 245 | foreach ($this->vars['conversions'] as $hex => $conv) { 246 | $scheme = scheme::rgb($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], 'shades'); 247 | $this->assertEquals(5, count($scheme)); 248 | $this->assertEquals($scheme[0], $conv['rgb']); 249 | foreach ($scheme as $key => $color) { 250 | $this->assertEquals(['r', 'g', 'b'], array_keys($color)); 251 | $diff = $color; 252 | regulate::rgb_array($color); 253 | $this->assertEquals($diff, $color); 254 | } 255 | } 256 | } 257 | 258 | /** 259 | * @test 260 | */ 261 | public function ReturnHSL() { 262 | foreach ($this->vars['conversions'] as $hex => $conv) { 263 | $scheme = scheme::hsl($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], 'shades'); 264 | $this->assertEquals(5, count($scheme)); 265 | $this->assertEquals($scheme[0], $conv['hsl']); 266 | foreach ($scheme as $key => $color) { 267 | $this->assertEquals(['h', 's', 'l'], array_keys($color)); 268 | $diff = $color; 269 | regulate::hsl_array($color); 270 | $this->assertEquals($diff, $color); 271 | } 272 | } 273 | } 274 | 275 | /** 276 | * @test 277 | */ 278 | public function ReturnHSB() { 279 | foreach ($this->vars['conversions'] as $hex => $conv) { 280 | $scheme = scheme::hsb($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], 'shades'); 281 | $this->assertEquals(5, count($scheme)); 282 | $this->assertEquals($scheme[0], $conv['hsb']); 283 | foreach ($scheme as $key => $color) { 284 | $this->assertEquals(['h', 's', 'b'], array_keys($color)); 285 | $diff = $color; 286 | regulate::hsb_array($color); 287 | $this->assertEquals($diff, $color); 288 | } 289 | } 290 | } 291 | 292 | /** 293 | * @test 294 | */ 295 | public function ReturnHex() { 296 | foreach ($this->vars['conversions'] as $hex => $conv) { 297 | $scheme = scheme::hex($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], 'shades'); 298 | $this->assertEquals(5, count($scheme)); 299 | $this->assertEquals($scheme[0], $hex); 300 | foreach ($scheme as $key => $color) { 301 | $diff = $color; 302 | regulate::hex($color); 303 | $this->assertEquals($diff, $color); 304 | } 305 | } 306 | } 307 | 308 | /** 309 | * @test 310 | */ 311 | public function ReturnCMYK() { 312 | foreach ($this->vars['conversions'] as $hex => $conv) { 313 | $scheme = scheme::cmyk($conv['hsl']['h'], $conv['hsl']['s'], $conv['hsl']['l'], 'shades'); 314 | $this->assertEquals(5, count($scheme)); 315 | $this->assertEquals($scheme[0], $conv['cmyk']); 316 | foreach ($scheme as $key => $color) { 317 | $this->assertEquals(['c', 'm', 'y', 'k'], array_keys($color)); 318 | $diff = $color; 319 | regulate::cmyk_array($color); 320 | $this->assertEquals($diff, $color); 321 | } 322 | } 323 | } 324 | 325 | /** 326 | * @test 327 | */ 328 | public function Error() { 329 | $hsl = $this->vars['conversions']['FFFFFF']['hsl']; 330 | $result = scheme::hsl($hsl['h'], $hsl['s'], $hsl['l'], 'invalid'); 331 | $this->assertEquals([], $result); 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /testing/tests/07_CacheTest.php: -------------------------------------------------------------------------------- 1 | set('test', 'id', $rand); 19 | $this->assertEquals($rand, $cache->get('test', 'id')); 20 | } 21 | 22 | /** 23 | * @test 24 | */ 25 | public function Is_Active() { 26 | $cache = new cache; 27 | $cache->active = FALSE; 28 | $rand = rand(); 29 | 30 | $cache->set('test', 'id', $rand); 31 | $this->assertEquals(NULL, $cache->get('test', 'id')); 32 | } 33 | 34 | /** 35 | * @test 36 | */ 37 | public function Reset() { 38 | $cache = new cache; 39 | $rand = rand(); 40 | 41 | $cache->set('test', 'id', $rand); 42 | $this->assertEquals($rand, $cache->get('test', 'id')); 43 | $cache->reset(); 44 | $this->assertEquals(NULL, $cache->get('test', 'id')); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /testing/tests/08_HSLTest.php: -------------------------------------------------------------------------------- 1 | 0, 17 | 'g' => 0, 18 | 'b' => 0, 19 | ]); 20 | $this->assertTrue(isset($hsl['h'])); 21 | $this->assertTrue(isset($hsl['s'])); 22 | $this->assertTrue(isset($hsl['l'])); 23 | } 24 | 25 | /** 26 | * @test 27 | */ 28 | public function Array_Access() { 29 | $hsl = new hsl([ 30 | 'r' => 255, 31 | 'g' => 0, 32 | 'b' => 0, 33 | ]); 34 | $this->assertTrue(isset($hsl['h'])); 35 | $this->assertEquals(50, $hsl['l']); 36 | $hsl['l'] = 100; 37 | $this->assertEquals(100, $hsl['l']); 38 | unset($hsl['l']); 39 | $this->assertEquals(0, $hsl['l']); 40 | unset($hsl['x']); // invalid unset 41 | } 42 | 43 | /** 44 | * @test 45 | */ 46 | public function Invoke() { 47 | $hsl = new hsl([ 48 | 'r' => 255, 49 | 'g' => 0, 50 | 'b' => 0, 51 | ]); 52 | $this->assertEquals([ 53 | 'h' => 0, 54 | 's' => 100, 55 | 'l' => 50 56 | ], $hsl()); 57 | } 58 | 59 | 60 | /** 61 | * @test 62 | * @expectedException Exception 63 | * @expectedExceptionMessage The offset "x" does not exist in projectcleverweb\color\hsl 64 | */ 65 | public function Invalid_Get() { 66 | error::set('active', TRUE); 67 | $hsl = new hsl([ 68 | 'r' => 255, 69 | 'g' => 0, 70 | 'b' => 0, 71 | ]); 72 | $hsl['x']; 73 | } 74 | 75 | /** 76 | * @test 77 | * @expectedException Exception 78 | * @expectedExceptionMessage The offset "x" cannot be set in projectcleverweb\color\hsl 79 | */ 80 | public function Invalid_Set() { 81 | error::set('active', TRUE); 82 | $hsl = new hsl([ 83 | 'r' => 255, 84 | 'g' => 0, 85 | 'b' => 0, 86 | ]); 87 | $hsl['x'] = 100; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /testing/tests/09_ColorTest.php: -------------------------------------------------------------------------------- 1 | vars['conversions']['FF0000']; 16 | foreach ($color as $type => $val) { 17 | $this->assertEquals($type, color::get_type($val)); 18 | } 19 | $this->assertEquals('error', color::get_type(new \stdClass)); 20 | $this->assertEquals('error', color::get_type(['invalid array'])); 21 | } 22 | 23 | /** 24 | * @test 25 | */ 26 | public function Import() { 27 | foreach ($this->vars['conversions'] as $color) { 28 | foreach ($color as $type => $val) { 29 | $import = new color($val); 30 | $this->assertEquals($color['rgb'], $import->rgb); 31 | } 32 | } 33 | } 34 | 35 | /** 36 | * @test 37 | */ 38 | public function Import_Color() { 39 | foreach ($this->vars['conversions'] as $color) { 40 | foreach ($color as $type => $val) { 41 | $color1 = new color($val); 42 | $color2 = new color($color1); 43 | $this->assertEquals($color['rgb'], $color1->rgb); 44 | $this->assertEquals($color['rgb'], $color1->rgb); 45 | $this->assertTrue($color1 !== $color2); 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * @test 52 | * @expectedException Exception 53 | * @expectedExceptionMessage The color supplied to projectcleverweb\color\color's constructor was not valid 54 | */ 55 | public function Import_Error() { 56 | $color = new color(new \stdClass); 57 | $this->assertEquals(0, $color->rgb['r']); 58 | $this->assertEquals(0, $color->rgb['g']); 59 | $this->assertEquals(0, $color->rgb['b']); 60 | error::set('active', TRUE); 61 | $color = new color(new \stdClass); 62 | } 63 | 64 | /** 65 | * @test 66 | */ 67 | public function Alpha() { 68 | $color = $this->vars['conversions']['FF0000']; 69 | $obj = new color($color['rgb'] + ['a' => 50.0]); 70 | $this->assertEquals(50.0, $obj->alpha()); 71 | $this->assertEquals(90.0, $obj->alpha(90)); 72 | $this->assertEquals(90.0, $obj->alpha()); 73 | } 74 | 75 | /** 76 | * @test 77 | */ 78 | public function As_HSL() { 79 | $color = new color($this->vars['conversions']['FF0000']['rgb']); 80 | $hsl = $color->hsl(); 81 | $this->assertEquals(0, $hsl['h']); 82 | $this->assertEquals(100, $hsl['s']); 83 | $this->assertEquals(50, $hsl['l']); 84 | } 85 | 86 | /** 87 | * @test 88 | */ 89 | public function Serialize() { 90 | $color = new color($this->vars['conversions']['FF0000']['rgb']); 91 | $serialized = serialize($color); 92 | $this->assertEquals('C:28:"projectcleverweb\color\color":29:{{"r":255,"g":0,"b":0,"a":100}}', $serialized); 93 | $this->assertEquals($color, unserialize($serialized)); 94 | } 95 | 96 | /** 97 | * @test 98 | */ 99 | public function JSON_Serialize() { 100 | $color = new color($this->vars['conversions']['FF0000']['rgb']); 101 | $json = json_encode($color); 102 | $this->assertEquals('{"r":255,"g":0,"b":0,"a":100}', $json); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /testing/tests/10_MainTest.php: -------------------------------------------------------------------------------- 1 | vars['conversions']['FF0000']; 16 | $main = new main($color['rgb']); 17 | $this->assertEquals($color['rgb'] + ['a' => 100], $main->rgb()); 18 | $this->assertEquals($color['hsl'] + ['a' => 100], $main->hsl()); 19 | $this->assertEquals($color['hsb'] + ['a' => 100], $main->hsb()); 20 | $this->assertEquals($color['cmyk'] + ['a' => 100], $main->cmyk()); 21 | $this->assertEquals($color['hex'], $main->hex()); 22 | $this->assertEquals($color['hex'], $main->web_safe()); 23 | $this->assertEquals('#'.$color['hex'], $main->css()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /testing/tests/11_CSSTest.php: -------------------------------------------------------------------------------- 1 |