From d458264be1449a1e1e96ba6053f0e7ae0b42ed47 Mon Sep 17 00:00:00 2001 From: Nefy Date: Sun, 15 May 2022 09:54:00 -0500 Subject: [PATCH] first commit --- .styleci.yml | 4 + CHANGELOG.md | 7 + CONTRIBUTING.md | 55 +++++ LICENSE.md | 21 ++ README.md | 57 +++++ art/banner.png | Bin 0 -> 8659 bytes art/preview.png | Bin 0 -> 28093 bytes composer.json | 41 ++++ config/cat.php | 117 ++++++++++ config/config.php | 40 ++++ config/dog.php | 116 ++++++++++ src/Facades/PetAvatar.php | 18 ++ src/PetAvatar.php | 70 ++++++ src/PetAvatarServiceProvider.php | 36 ++++ src/Utilities/RandomColor.php | 360 +++++++++++++++++++++++++++++++ 15 files changed, 942 insertions(+) create mode 100644 .styleci.yml create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 art/banner.png create mode 100644 art/preview.png create mode 100644 composer.json create mode 100644 config/cat.php create mode 100644 config/config.php create mode 100644 config/dog.php create mode 100644 src/Facades/PetAvatar.php create mode 100644 src/PetAvatar.php create mode 100644 src/PetAvatarServiceProvider.php create mode 100644 src/Utilities/RandomColor.php diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 0000000..f4d3cbc --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,4 @@ +preset: laravel + +disabled: + - single_class_element_per_statement diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..385326c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to `pet-avatar` will be documented in this file + +## 1.0.0 - 201X-XX-XX + +- initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b4ae1c4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +Please read and understand the contribution guide before creating an issue or pull request. + +## Etiquette + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code +held within. They make the code freely available in the hope that it will be of use to other developers. It would be +extremely unfair for them to suffer abuse or anger for their hard work. + +Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the +world that developers are civilized and selfless people. + +It's the duty of the maintainer to ensure that all submissions to the project are of sufficient +quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. + +## Viability + +When requesting or submitting new features, first consider whether it might be useful to others. Open +source projects are used by many developers, who may have entirely different needs to your own. Think about +whether or not your feature is likely to be used by other users of the project. + +## Procedure + +Before filing an issue: + +- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. +- Check to make sure your feature suggestion isn't already present within the project. +- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. +- Check the pull requests tab to ensure that the feature isn't already in progress. + +Before submitting a pull request: + +- Check the codebase to ensure that your feature doesn't already exist. +- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. + +## Requirements + +If the project maintainer has any additional requirements, you will find them listed here. + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + +**Happy coding**! diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..2886c83 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Nefy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..6aaa9ce --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +![Banner](art/banner.png) + +# Pet Avatar + +Generate a random cute avatar using the GD Library + +## Preview + +![Preview](art/preview.png) + +## Requirements + +- PHP 7.4 or later +- PHP GD extension must be enabled + +## Installation + +You can install the package via composer: + +```bash +composer require nefydev/pet-avatar +``` +To setup the config file: + +```bash +php artisan vendor:publish --provider="Nefydev\PetAvatar\PetAvatarServiceProvider" +``` + +## Usage + +```php + use Nefydev\PetAvatar\Facades\PetAvatar; + ... + + // generate a cute random avatar + $avatar = PetAvatar::generate(); + + // shows the file name + echo $avatar; +``` + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Credits + +- [Nefy](https://github.com/nefydev) +- [All Contributors](https://github.com/nefydev/pet-avatar/contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. + +## Support + +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/E1E5BQUXC) \ No newline at end of file diff --git a/art/banner.png b/art/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..fafd56760d9c5b8a21a6085fd7bf48bed40d8359 GIT binary patch literal 8659 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 Q0QhmTU%#sKJNBNx0!6jD00000 literal 0 HcmV?d00001 diff --git a/art/preview.png b/art/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..a492f931ce3b3751c1ef0e75f5b398831b40019b GIT binary patch literal 28093 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 Q3J`zp%RQD=EJf4*4~%c$hyVZp literal 0 HcmV?d00001 diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..7aecd96 --- /dev/null +++ b/composer.json @@ -0,0 +1,41 @@ +{ + "name": "nefydev/pet-avatar", + "description": "Cute avatar generator.", + "keywords": [ + "laravel", + "laravel-package", + "avatar", + "pet-avatar" + ], + "homepage": "https://github.com/nefydev/pet-avatar", + "license": "MIT", + "authors": [ + { + "name": "Nefy", + "email": "info@nefy.dev", + "role": "Developer" + } + ], + "require": { + "php": "^7.4|^8.0", + "illuminate/support": "^8.0" + }, + "autoload": { + "psr-4": { + "Nefydev\\PetAvatar\\": "src" + } + }, + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "Nefydev\\PetAvatar\\PetAvatarServiceProvider" + ], + "aliases": { + "PetAvatar": "Nefydev\\PetAvatar\\Facades\\PetAvatar" + } + } + } +} diff --git a/config/cat.php b/config/cat.php new file mode 100644 index 0000000..cd8c14d --- /dev/null +++ b/config/cat.php @@ -0,0 +1,117 @@ + [ + 'head' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'light', + 'hue' => ['monochrome', 'orange', 'yellow'] + ], + 'variations' => [ + [ + [11, 1, 2, 1], + [10, 2, 3, 1], + [4, 1, 2, 1], + [4, 2, 3, 1], + [4, 8, 4, 1], + [3, 10, 5, 2], + [2, 12, 7, 3] + ] + ] + ], + 'spot' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'light', + 'hue' => 'monochrome' + ], + 'variations' => [ + [ + [3, 10, 10, 1], + [4, 8, 11, 1], + [5, 6, 12, 1], + [5, 6, 9, 1] + ], + [ + [3, 10, 10, 1], + [4, 8, 11, 1], + [5, 6, 12, 1], + [5, 6, 9, 1], + [3, 1, 5, 2], + [4, 1, 2, 4], + [5, 1, 3, 3], + [6, 1, 4, 1] + ], + [ + [3, 10, 10, 1], + [4, 8, 11, 1], + [5, 6, 12, 1], + [5, 6, 9, 1], + [12, 1, 5, 2], + [11, 1, 2, 4], + [10, 1, 3, 3], + [9, 1, 4, 1] + ], + ] + ], + 'ears' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'light', + 'hue' => ['monochrome', 'pink'] + ], + 'variations' => [[ + [4, 2, 4, 2], + [11, 2, 4, 2] + ]] + ], + 'collar' => [ + 'colors' => [ + 'format' => 'rgb', + 'hue' => ['random'] + ], + 'variations' => [[ + [5, 6, 13, 1] + ]] + ], + 'eyes' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'dark', + 'hue' => 'monochrome' + ], + 'variations' => [ + [ + [6, 1, 8, 2], + [6, 2, 9, 1], + [10, 1, 8, 2], + [10, 2, 9, 1] + ], + [ + [5, 3, 9, 1], + [10, 3, 9, 1] + ], + ] + ], + 'nose' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'light', + 'hue' => 'pink' + ], + 'variations' => [ + [ + [8, 2, 10, 2], + [7, 2, 11, 1], + [9, 2, 11, 1] + ], + [ + [9, 2, 10, 2], + [8, 2, 11, 1] + ] + ] + ] + ], + 'small_parts' => ['eyes', 'nose', 'ears'] +]; diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..3a539b2 --- /dev/null +++ b/config/config.php @@ -0,0 +1,40 @@ + 'cat', + + /* + |-------------------------------------------------------------------------- + | File type + |-------------------------------------------------------------------------- + | + | The image file type. + | Possible values: jpeg, png, gif + | Default: png + | + */ + 'file' => 'png', + + /* + |-------------------------------------------------------------------------- + | Path + |-------------------------------------------------------------------------- + | + | The path where the files will be stored. relative to public. + | Default: public/avatars + | + */ + 'path' => 'avatars', + +]; diff --git a/config/dog.php b/config/dog.php new file mode 100644 index 0000000..c6a4ce7 --- /dev/null +++ b/config/dog.php @@ -0,0 +1,116 @@ + [ + 'head' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'light', + 'hue' => ['monochrome', 'orange'] + ], + 'variations' => [[ + [5, 6, 2, 1], + [4, 8, 3, 7] + ]] + ], + 'spot' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'light', + 'hue' => 'monochrome' + ], + 'variations' => [ + [ + [7, 2, 8, 1], + [6, 4, 9, 1], + [4, 8, 10, 3] + ], + [ + [7, 2, 8, 1], + [6, 4, 9, 1], + [4, 8, 10, 3], + [4, 1, 3, 2], + [5, 2, 2, 2], + [7, 1, 2, 1] + ], + [ + [7, 2, 8, 1], + [6, 4, 9, 1], + [4, 8, 10, 3], + [11, 1, 3, 2], + [9, 2, 2, 2], + [8, 1, 2, 1] + + ], + ] + ], + 'ears' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'dark', + 'hue' => ['orange', 'monochrome'] + ], + 'variations' => [[ + [3, 1, 4, 9], + [2, 1, 5, 7], + [12, 1, 4, 9], + [13, 1, 5, 7] + ]] + ], + 'collar' => [ + 'colors' => [ + 'format' => 'rgb', + 'hue' => ['random'] + ], + 'variations' => [[ + [5, 6, 13, 1] + ]] + ], + 'eyes' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'dark', + 'hue' => 'monochrome' + ], + 'variations' => [ + [ + [5, 1, 7, 3], + [5, 2, 8, 1], + [10, 1, 7, 3], + [10, 2, 8, 1] + ], + [ + [5, 3, 8, 1], + [10, 3, 8, 1] + ], + ] + ], + 'nose' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'dark', + 'hue' => 'monochrome' + ], + 'variations' => [ + [[7, 2, 10, 1]] + ] + ], + 'mouth' => [ + 'colors' => [ + 'format' => 'rgb', + 'luminosity' => 'dark', + 'hue' => 'red' + ], + 'variations' => [ + [ + [6, 2, 11, 2] + ], + [ + [9, 2, 11, 2] + ] + + ] + ] + ], + 'small_parts' => ['eyes', 'mouth'] +]; diff --git a/src/Facades/PetAvatar.php b/src/Facades/PetAvatar.php new file mode 100644 index 0000000..0a31880 --- /dev/null +++ b/src/Facades/PetAvatar.php @@ -0,0 +1,18 @@ +config = $this->validateConfig(config('pet-avatar')); + } + + public function generate() + { + $pet = $this->config['pet']; + + $parts = []; + foreach (array_keys(config("{$pet}.parts")) as $part) { + $pos = array_rand(config("{$pet}.parts.{$part}.variations")); + $parts[$part] = config("{$pet}.parts.{$part}.variations.{$pos}"); + } + + $image = imagecreate(320, 320); + $background = RandomColor::one(array('format' => 'rgb')); + imagefilltoborder($image, 0, 0, imagecolorallocate($image, $background['r'], $background['g'], $background['b']), imagecolorallocate($image, $background['r'], $background['g'], $background['b'])); + + $unit1 = 20; + $unit2 = 10; + + foreach ($parts as $name => $part) { + $color = RandomColor::one(config("{$pet}.parts.{$name}.colors")); + foreach ($part as $col) { + $unit = in_array($name, config("{$pet}.small_parts")) ? $unit2 : $unit1; + $x1 = $col[0] * $unit1; + $x2 = $x1 + ($col[1] * $unit); + $y1 = $col[2] * $unit1; + $y2 = $y1 + ($col[3] * $unit); + imagefilledrectangle($image, $x1, $y1, $x2, $y2, imagecolorallocate($image, $color['r'], $color['g'], $color['b'])); + } + } + + $name = uniqid() . '.' . $this->config['file']; + $path = $this->config['path'] . '/' . $name; + + $this->config['function']($image, $path); + imagedestroy($image); + + return $name; + } + + public function validateConfig(array $config) + { + $config['pet'] = in_array($config['pet'], ['cat', 'dog']) ? $config['pet'] : 'cat'; + $config['file'] = in_array($config['file'], ['jpeg', 'png', 'gif']) ? $config['file'] : 'png'; + $config['path'] = $config['path'] == '' ? public_path('avatars') : public_path($config['path']); + $config['function'] = "image{$config['file']}"; + + if (!is_dir($config['path']) && !mkdir($config['path'], 0777, true)) { + throw new Exception( + "PetAvatar - Export folder could not be instantiated ({$config['path']})" + ); + } + + return $config; + } +} diff --git a/src/PetAvatarServiceProvider.php b/src/PetAvatarServiceProvider.php new file mode 100644 index 0000000..19f2612 --- /dev/null +++ b/src/PetAvatarServiceProvider.php @@ -0,0 +1,36 @@ +app->runningInConsole()) { + $this->publishes([ + __DIR__.'/../config/config.php' => config_path('pet-avatar.php'), + ], 'config'); + } + } + + /** + * Register the application services. + */ + public function register() + { + // Automatically apply the package configuration + $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'pet-avatar'); + $this->mergeConfigFrom(__DIR__.'/../config/cat.php', 'cat'); + $this->mergeConfigFrom(__DIR__.'/../config/dog.php', 'dog'); + + // Register the main class to use with the facade + $this->app->singleton('pet-avatar', function () { + return new PetAvatar; + }); + } +} diff --git a/src/Utilities/RandomColor.php b/src/Utilities/RandomColor.php new file mode 100644 index 0000000..e582d58 --- /dev/null +++ b/src/Utilities/RandomColor.php @@ -0,0 +1,360 @@ += 0) { + $ranges[] = array($hue, $hue); + } + } + } + } + + if (($l = count($ranges)) === 0) { + return array(0, 360); + } else if ($l === 1) { + return $ranges[0]; + } else { + return $ranges[self::_rand(array(0, $l - 1), $options)]; + } + } + + static private function _getMinimumBrightness($h, $s) + { + $colorInfo = self::_getColorInfo($h); + $bounds = $colorInfo['bounds']; + + for ($i = 0, $l = count($bounds); $i < $l - 1; $i++) { + $s1 = $bounds[$i][0]; + $v1 = $bounds[$i][1]; + $s2 = $bounds[$i + 1][0]; + $v2 = $bounds[$i + 1][1]; + + if ($s >= $s1 && $s <= $s2) { + $m = ($v2 - $v1) / ($s2 - $s1); + $b = $v1 - $m * $s1; + return round($m * $s + $b); + } + } + + return 0; + } + + static private function _getColorInfo($h) + { + // Maps red colors to make picking hue easier + if ($h >= 334 && $h <= 360) { + $h -= 360; + } + + foreach (self::$dictionary as $color) { + if ($color['h'] !== null && $h >= $color['h'][0] && $h <= $color['h'][1]) { + return $color; + } + } + } + + static private function _rand($bounds, $options) + { + if (isset($options['prng'])) { + return $options['prng']($bounds[0], $bounds[1]); + } else { + return mt_rand($bounds[0], $bounds[1]); + } + } + + static public function hsv2hex($hsv) + { + $rgb = self::hsv2rgb($hsv); + $hex = '#'; + + foreach ($rgb as $c) { + $hex .= str_pad(dechex($c), 2, '0', STR_PAD_LEFT); + } + + return $hex; + } + + static public function hsv2hsl($hsv) + { + extract($hsv); + + $s /= 100; + $v /= 100; + $k = (2 - $s) * $v; + + return array( + 'h' => $h, + 's' => round($s * $v / ($k < 1 ? $k : 2 - $k), 4) * 100, + 'l' => $k / 2 * 100, + ); + } + + static public function hsv2rgb($hsv) + { + extract($hsv); + + $h /= 360; + $s /= 100; + $v /= 100; + + $i = floor($h * 6); + $f = $h * 6 - $i; + + $m = $v * (1 - $s); + $n = $v * (1 - $s * $f); + $k = $v * (1 - $s * (1 - $f)); + + $r = 1; + $g = 1; + $b = 1; + + switch ($i) { + case 0: + list($r, $g, $b) = array($v, $k, $m); + break; + case 1: + list($r, $g, $b) = array($n, $v, $m); + break; + case 2: + list($r, $g, $b) = array($m, $v, $k); + break; + case 3: + list($r, $g, $b) = array($m, $n, $v); + break; + case 4: + list($r, $g, $b) = array($k, $m, $v); + break; + case 5: + case 6: + list($r, $g, $b) = array($v, $m, $n); + break; + } + + return array( + 'r' => floor($r * 255), + 'g' => floor($g * 255), + 'b' => floor($b * 255), + ); + } +} + +/* + * h=hueRange + * s=saturationRange : bounds[0][0] ; bounds[-][0] + */ +RandomColor::$dictionary = array( + 'monochrome' => array( + 'bounds' => array(array(0, 0), array(100, 0)), + 'h' => NULL, + 's' => array(0, 100) + ), + 'red' => array( + 'bounds' => array(array(20, 100), array(30, 92), array(40, 89), array(50, 85), array(60, 78), array(70, 70), array(80, 60), array(90, 55), array(100, 50)), + 'h' => array(-26, 18), + 's' => array(20, 100) + ), + 'orange' => array( + 'bounds' => array(array(20, 100), array(30, 93), array(40, 88), array(50, 86), array(60, 85), array(70, 70), array(100, 70)), + 'h' => array(19, 46), + 's' => array(20, 100) + ), + 'yellow' => array( + 'bounds' => array(array(25, 100), array(40, 94), array(50, 89), array(60, 86), array(70, 84), array(80, 82), array(90, 80), array(100, 75)), + 'h' => array(47, 62), + 's' => array(25, 100) + ), + 'green' => array( + 'bounds' => array(array(30, 100), array(40, 90), array(50, 85), array(60, 81), array(70, 74), array(80, 64), array(90, 50), array(100, 40)), + 'h' => array(63, 178), + 's' => array(30, 100) + ), + 'blue' => array( + 'bounds' => array(array(20, 100), array(30, 86), array(40, 80), array(50, 74), array(60, 60), array(70, 52), array(80, 44), array(90, 39), array(100, 35)), + 'h' => array(179, 257), + 's' => array(20, 100) + ), + 'purple' => array( + 'bounds' => array(array(20, 100), array(30, 87), array(40, 79), array(50, 70), array(60, 65), array(70, 59), array(80, 52), array(90, 45), array(100, 42)), + 'h' => array(258, 282), + 's' => array(20, 100) + ), + 'pink' => array( + 'bounds' => array(array(20, 100), array(30, 90), array(40, 86), array(60, 84), array(80, 80), array(90, 75), array(100, 73)), + 'h' => array(283, 334), + 's' => array(20, 100) + ) +);