From 8ac69590cf9c81826a891979b60150f72970b06c Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 26 Oct 2022 06:53:56 +0200 Subject: [PATCH] add new Jdenticon comment icon library, set it as default, fixes #793 --- cfg/conf.sample.php | 5 +- composer.json | 3 +- composer.lock | 695 ++++++++---------- lib/Configuration.php | 2 +- lib/Model/Comment.php | 13 +- tst/ModelTest.php | 13 +- vendor/composer/ClassLoader.php | 157 +++- vendor/composer/InstalledVersions.php | 350 +++++++++ vendor/composer/autoload_classmap.php | 39 + vendor/composer/autoload_psr4.php | 1 + vendor/composer/autoload_real.php | 15 +- vendor/composer/autoload_static.php | 47 ++ vendor/composer/installed.php | 59 ++ vendor/composer/platform_check.php | 26 + .../jdenticon/jdenticon/src/Canvas/Canvas.php | 130 ++++ .../jdenticon/src/Canvas/CanvasContext.php | 408 ++++++++++ .../jdenticon/src/Canvas/ColorUtils.php | 228 ++++++ .../jdenticon/jdenticon/src/Canvas/Matrix.php | 141 ++++ .../jdenticon/src/Canvas/Png/PngBuffer.php | 92 +++ .../jdenticon/src/Canvas/Png/PngEncoder.php | 238 ++++++ .../jdenticon/src/Canvas/Png/PngPalette.php | 92 +++ .../jdenticon/jdenticon/src/Canvas/Point.php | 41 ++ .../src/Canvas/Rasterization/Edge.php | 44 ++ .../Canvas/Rasterization/EdgeIntersection.php | 27 + .../EdgeSuperSampleIntersection.php | 24 + .../src/Canvas/Rasterization/EdgeTable.php | 158 ++++ .../src/Canvas/Rasterization/Layer.php | 30 + .../src/Canvas/Rasterization/LayerManager.php | 150 ++++ .../src/Canvas/Rasterization/Rasterizer.php | 379 ++++++++++ .../Rasterization/SuperSampleBuffer.php | 198 +++++ .../Canvas/Rasterization/SuperSampleRange.php | 27 + vendor/jdenticon/jdenticon/src/Color.php | 605 +++++++++++++++ vendor/jdenticon/jdenticon/src/Identicon.php | 492 +++++++++++++ .../jdenticon/src/IdenticonStyle.php | 460 ++++++++++++ .../src/Rendering/AbstractRenderer.php | 209 ++++++ .../jdenticon/src/Rendering/ColorTheme.php | 84 +++ .../jdenticon/src/Rendering/IconGenerator.php | 290 ++++++++ .../src/Rendering/ImagickRenderer.php | 296 ++++++++ .../src/Rendering/InternalPngRenderer.php | 123 ++++ .../jdenticon/src/Rendering/Point.php | 54 ++ .../jdenticon/src/Rendering/Rectangle.php | 60 ++ .../src/Rendering/RendererInterface.php | 141 ++++ .../jdenticon/src/Rendering/SvgPath.php | 83 +++ .../jdenticon/src/Rendering/SvgRenderer.php | 133 ++++ .../jdenticon/src/Rendering/Transform.php | 79 ++ .../src/Rendering/TriangleDirection.php | 35 + .../jdenticon/jdenticon/src/Shapes/Shape.php | 62 ++ .../jdenticon/src/Shapes/ShapeCategory.php | 71 ++ .../jdenticon/src/Shapes/ShapeDefinitions.php | 243 ++++++ .../jdenticon/src/Shapes/ShapePosition.php | 45 ++ 50 files changed, 6996 insertions(+), 401 deletions(-) create mode 100644 vendor/composer/InstalledVersions.php create mode 100644 vendor/composer/installed.php create mode 100644 vendor/composer/platform_check.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Canvas.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Matrix.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Point.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php create mode 100644 vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php create mode 100644 vendor/jdenticon/jdenticon/src/Color.php create mode 100644 vendor/jdenticon/jdenticon/src/Identicon.php create mode 100644 vendor/jdenticon/jdenticon/src/IdenticonStyle.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/Point.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/SvgPath.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/SvgRenderer.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/Transform.php create mode 100644 vendor/jdenticon/jdenticon/src/Rendering/TriangleDirection.php create mode 100644 vendor/jdenticon/jdenticon/src/Shapes/Shape.php create mode 100644 vendor/jdenticon/jdenticon/src/Shapes/ShapeCategory.php create mode 100644 vendor/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php create mode 100644 vendor/jdenticon/jdenticon/src/Shapes/ShapePosition.php diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php index 7afe7aae..ba6fff55 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -67,8 +67,9 @@ languageselection = false ; (optional) IP based icons are a weak mechanism to detect if a comment was from ; a different user when the same username was used in a comment. It might be ; used to get the IP of a non anonymous comment poster if the server salt is -; leaked and a SHA256 HMAC rainbow table is generated for all (relevant) IPs. -; Can be set to one these values: "none" / "vizhash" / "identicon" (default). +; leaked and a SHA512 HMAC rainbow table is generated for all (relevant) IPs. +; Can be set to one these values: +; "none" / "vizhash" / "identicon" / "jdenticon" (default). ; icon = "none" ; Content Security Policy headers allow a website to restrict what sources are diff --git a/composer.json b/composer.json index 01d384f2..6e99d5de 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ "php" : "^5.6.0 || ^7.0 || ^8.0", "paragonie/random_compat" : "2.0.21", "yzalis/identicon" : "2.0.0", - "mlocati/ip-lib" : "1.18.0" + "mlocati/ip-lib" : "1.18.0", + "jdenticon/jdenticon": "^1.0" }, "suggest" : { "google/cloud-storage" : "1.26.1", diff --git a/composer.lock b/composer.lock index a159dd80..17948976 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,57 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fa52d4988bfe17d4b27e3a4789a1ec49", + "content-hash": "17bceced29627163f7aa330a0697f68b", "packages": [ + { + "name": "jdenticon/jdenticon", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/dmester/jdenticon-php.git", + "reference": "994ee07293fb978f983393ffcb2c0250592a6ac4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/994ee07293fb978f983393ffcb2c0250592a6ac4", + "reference": "994ee07293fb978f983393ffcb2c0250592a6ac4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jdenticon\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Mester Pirttijärvi" + } + ], + "description": "Render PNG and SVG identicons.", + "homepage": "https://jdenticon.com/", + "keywords": [ + "avatar", + "identicon", + "jdenticon" + ], + "support": { + "docs": "https://jdenticon.com/php-api.html", + "issues": "https://github.com/dmester/jdenticon-php/issues", + "source": "https://github.com/dmester/jdenticon-php" + }, + "time": "2022-07-02T11:03:15+00:00" + }, { "name": "mlocati/ip-lib", "version": "1.18.0", @@ -61,6 +110,10 @@ "range", "subnet" ], + "support": { + "issues": "https://github.com/mlocati/ip-lib/issues", + "source": "https://github.com/mlocati/ip-lib/tree/1.18.0" + }, "funding": [ { "url": "https://github.com/sponsors/mlocati", @@ -120,6 +173,11 @@ "pseudorandom", "random" ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, "time": "2022-02-16T17:07:03+00:00" }, { @@ -172,6 +230,10 @@ "identicon", "image" ], + "support": { + "issues": "https://github.com/yzalis/Identicon/issues", + "source": "https://github.com/yzalis/Identicon/tree/master" + }, "abandoned": true, "time": "2019-10-14T09:30:57+00:00" } @@ -179,29 +241,30 @@ "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^9", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" }, "type": "library", "autoload": { @@ -226,6 +289,10 @@ "constructor", "instantiate" ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + }, "funding": [ { "url": "https://www.doctrine-project.org/sponsorship.html", @@ -240,32 +307,33 @@ "type": "tidelift" } ], - "time": "2020-11-10T18:47:58+00:00" + "time": "2022-03-03T08:28:38+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { @@ -288,97 +356,53 @@ "object", "object graph" ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, "funding": [ { "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", "type": "tidelift" } ], - "time": "2020-11-13T09:40:50+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2020-06-27T09:03:43+00:00" + "time": "2022-03-03T13:19:32+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b", + "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b", "shasum": "" }, "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" + "php": ">=5.3.3" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" + "psr-0": { + "phpDocumentor": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", @@ -388,96 +412,46 @@ "authors": [ { "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "mike.vanriel@naenius.com" } ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2021-10-19T17:43:47+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/2.x" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", - "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2022-01-04T19:58:01+00:00" + "time": "2016-01-25T08:17:30+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.10.3", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "451c3cd1418cf640de218914901e51b064abb093" + "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", - "reference": "451c3cd1418cf640de218914901e51b064abb093", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7", + "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + "phpdocumentor/reflection-docblock": "~2.0", + "sebastian/comparator": "~1.1" }, "require-dev": { - "phpspec/phpspec": "^2.5 || ^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + "phpspec/phpspec": "~2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10.x-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" + "psr-0": { + "Prophecy\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -505,44 +479,48 @@ "spy", "stub" ], - "time": "2020-03-05T15:02:03+00:00" + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/master" + }, + "time": "2015-08-13T10:07:40+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "4.0.8", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + "reference": "85f5db2d0a0da79ad6a256eb54148ba383059ad9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", - "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85f5db2d0a0da79ad6a256eb54148ba383059ad9", + "reference": "85f5db2d0a0da79ad6a256eb54148ba383059ad9", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^5.6 || ^7.0", - "phpunit/php-file-iterator": "^1.3", - "phpunit/php-text-template": "^1.2", - "phpunit/php-token-stream": "^1.4.2 || ^2.0", - "sebastian/code-unit-reverse-lookup": "^1.0", - "sebastian/environment": "^1.3.2 || ^2.0", - "sebastian/version": "^1.0 || ^2.0" + "php": ">=5.6", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/code-unit-reverse-lookup": "~1.0", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0|~2.0" }, "require-dev": { - "ext-xdebug": "^2.1.4", - "phpunit/phpunit": "^5.7" + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~5" }, "suggest": { - "ext-xdebug": "^2.5.1" + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-master": "3.2.x-dev" } }, "autoload": { @@ -568,7 +546,12 @@ "testing", "xunit" ], - "time": "2017-04-02T07:44:40+00:00" + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/3.2.0" + }, + "time": "2016-02-13T06:47:56+00:00" }, { "name": "phpunit/php-file-iterator", @@ -615,6 +598,11 @@ "filesystem", "iterator" ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5" + }, "time": "2017-11-27T13:52:08+00:00" }, { @@ -656,32 +644,36 @@ "keywords": [ "template" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -696,7 +688,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -705,33 +697,43 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "1.4.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "~4.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -754,55 +756,51 @@ "keywords": [ "tokenizer" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/1.4" + }, "abandoned": true, - "time": "2017-11-27T05:48:46+00:00" + "time": "2017-12-04T08:55:13+00:00" }, { "name": "phpunit/phpunit", - "version": "5.7.27", + "version": "5.2.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" + "reference": "073701643835376cb2f15dc005ea8933f8d4edbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", - "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/073701643835376cb2f15dc005ea8933f8d4edbd", + "reference": "073701643835376cb2f15dc005ea8933f8d4edbd", "shasum": "" }, "require": { "ext-dom": "*", "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", - "phpspec/prophecy": "^1.6.2", - "phpunit/php-code-coverage": "^4.0.4", + "php": ">=5.6", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~3.2", "phpunit/php-file-iterator": "~1.4", "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "^3.2", - "sebastian/comparator": "^1.2.4", - "sebastian/diff": "^1.4.3", - "sebastian/environment": "^1.3.4 || ^2.0", - "sebastian/exporter": "~2.0", - "sebastian/global-state": "^1.1", - "sebastian/object-enumerator": "~2.0", + "phpunit/php-timer": ">=1.0.6", + "phpunit/phpunit-mock-objects": ">=3.0.5", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", "sebastian/resource-operations": "~1.0", - "sebastian/version": "^1.0.6|^2.0.1", - "symfony/yaml": "~2.1|~3.0|~4.0" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2" - }, - "require-dev": { - "ext-pdo": "*" + "sebastian/version": "~1.0|~2.0", + "symfony/yaml": "~2.1|~3.0" }, "suggest": { - "ext-xdebug": "*", "phpunit/php-invoker": "~1.1" }, "bin": [ @@ -811,7 +809,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.7.x-dev" + "dev-master": "5.2.x-dev" } }, "autoload": { @@ -837,33 +835,35 @@ "testing", "xunit" ], - "time": "2018-02-01T05:50:59+00:00" + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/5.2.7" + }, + "time": "2016-02-18T06:39:51+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "3.4.4", + "version": "3.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" + "reference": "151c96874bff6fe61a25039df60e776613a61489" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/151c96874bff6fe61a25039df60e776613a61489", + "reference": "151c96874bff6fe61a25039df60e776613a61489", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", - "php": "^5.6 || ^7.0", - "phpunit/php-text-template": "^1.2", - "sebastian/exporter": "^1.2 || ^2.0" - }, - "conflict": { - "phpunit/phpunit": "<5.4.0" + "php": ">=5.6", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" }, "require-dev": { - "phpunit/phpunit": "^5.4" + "phpunit/phpunit": "~5" }, "suggest": { "ext-soap": "*" @@ -871,7 +871,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -896,8 +896,13 @@ "mock", "xunit" ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues", + "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/3.1" + }, "abandoned": true, - "time": "2017-06-30T09:13:00+00:00" + "time": "2016-04-20T14:39:26+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -942,6 +947,10 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -1012,27 +1021,31 @@ "compare", "equality" ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/1.2" + }, "time": "2017-01-29T09:50:25+00:00" }, { "name": "sebastian/diff", - "version": "1.4.3", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "~4.8" }, "type": "library", "extra": { @@ -1064,32 +1077,36 @@ "keywords": [ "diff" ], - "time": "2017-05-22T07:24:03+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/master" + }, + "time": "2015-12-08T07:14:41+00:00" }, { "name": "sebastian/environment", - "version": "2.0.0", + "version": "1.3.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "^5.0" + "phpunit/phpunit": "~4.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -1114,25 +1131,29 @@ "environment", "hhvm" ], - "time": "2016-11-26T07:53:53+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/1.3.7" + }, + "time": "2016-05-17T03:18:57+00:00" }, { "name": "sebastian/exporter", - "version": "2.0.0", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", "shasum": "" }, "require": { "php": ">=5.3.3", - "sebastian/recursion-context": "~2.0" + "sebastian/recursion-context": "~1.0" }, "require-dev": { "ext-mbstring": "*", @@ -1141,7 +1162,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -1181,7 +1202,11 @@ "export", "exporter" ], - "time": "2016-11-19T08:54:04+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/master" + }, + "time": "2016-06-17T09:04:28+00:00" }, { "name": "sebastian/global-state", @@ -1232,66 +1257,24 @@ "keywords": [ "global state" ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/1.1.1" + }, "time": "2015-10-12T03:26:01+00:00" }, - { - "name": "sebastian/object-enumerator", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", - "shasum": "" - }, - "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-02-18T15:18:39+00:00" - }, { "name": "sebastian/recursion-context", - "version": "2.0.0", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", "shasum": "" }, "require": { @@ -1303,7 +1286,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -1331,7 +1314,11 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-11-19T07:33:16+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/master" + }, + "time": "2016-10-03T07:41:43+00:00" }, { "name": "sebastian/resource-operations", @@ -1373,6 +1360,10 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/master" + }, "time": "2015-07-28T20:34:47+00:00" }, { @@ -1416,20 +1407,24 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, "time": "2016-10-03T07:35:21+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", "shasum": "" }, "require": { @@ -1444,7 +1439,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1452,12 +1447,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1481,6 +1476,9 @@ "polyfill", "portable" ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1495,31 +1493,31 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.37", + "version": "v3.4.47", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "d7f637cc0f0cc14beb0984f2bb50da560b271311" + "reference": "88289caa3c166321883f67fe5130188ebbb47094" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/d7f637cc0f0cc14beb0984f2bb50da560b271311", - "reference": "d7f637cc0f0cc14beb0984f2bb50da560b271311", + "url": "https://api.github.com/repos/symfony/yaml/zipball/88289caa3c166321883f67fe5130188ebbb47094", + "reference": "88289caa3c166321883f67fe5130188ebbb47094", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": "^5.5.9|>=7.0.8", "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/console": "<3.4" }, "require-dev": { - "symfony/console": "^3.4|^4.0|^5.0" + "symfony/console": "~3.4|~4.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -1547,8 +1545,11 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Loads and dumps YAML files", + "description": "Symfony Yaml Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v3.4.47" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1563,61 +1564,7 @@ "type": "tidelift" } ], - "time": "2022-01-24T20:11:01+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2021-03-09T10:59:23+00:00" + "time": "2020-10-24T10:57:07+00:00" } ], "aliases": [], @@ -1629,5 +1576,5 @@ "php": "^5.6.0 || ^7.0 || ^8.0" }, "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.2.0" } diff --git a/lib/Configuration.php b/lib/Configuration.php index 6f3a8225..f4e537ef 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -53,7 +53,7 @@ class Configuration 'languagedefault' => '', 'urlshortener' => '', 'qrcode' => true, - 'icon' => 'identicon', + 'icon' => 'jdenticon', 'cspheader' => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads', 'zerobincompatibility' => false, 'httpwarning' => true, diff --git a/lib/Model/Comment.php b/lib/Model/Comment.php index f9f45507..8e4142ee 100644 --- a/lib/Model/Comment.php +++ b/lib/Model/Comment.php @@ -14,6 +14,7 @@ namespace PrivateBin\Model; use Exception; use Identicon\Identicon; +use Jdenticon\Identicon as Jdenticon; use PrivateBin\Persistence\TrafficLimiter; use PrivateBin\Vizhash16x16; @@ -164,7 +165,17 @@ class Comment extends AbstractModel if ($icon != 'none') { $pngdata = ''; $hmac = TrafficLimiter::getHash(); - if ($icon == 'identicon') { + if ($icon == 'jdenticon') { + $jdenticon = new Jdenticon(array( + 'hash' => $hmac, + 'size' => 16, + 'style' => array( + 'backgroundColor' => '#fff0', // fully transparent, for dark mode + 'padding' => 0, + ), + )); + $pngdata = $jdenticon->getImageDataUri('png'); + } elseif ($icon == 'identicon') { $identicon = new Identicon(); $pngdata = $identicon->getImageDataUri($hmac, 16); } elseif ($icon == 'vizhash') { diff --git a/tst/ModelTest.php b/tst/ModelTest.php index a88e0296..49a2ae6b 100644 --- a/tst/ModelTest.php +++ b/tst/ModelTest.php @@ -1,6 +1,6 @@ get(); $comment->store(); - $identicon = new Identicon(); - $pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16); + $identicon = new Identicon(array( + 'hash' => TrafficLimiter::getHash(), + 'size' => 16, + 'style' => array( + 'backgroundColor' => '#fff0', // fully transparent, for dark mode + 'padding' => 0, + ), + )); + $pngdata = $identicon->getImageDataUri('png'); $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']); $this->assertEquals($pngdata, $comment['meta']['icon'], 'icon gets set'); } diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index fce8549f..afef3fa2 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -37,57 +37,130 @@ namespace Composer\Autoload; * * @author Fabien Potencier * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { + /** @var ?string */ + private $vendorDir; + // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ private $fallbackDirsPsr4 = array(); // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ private $fallbackDirsPsr0 = array(); + /** @var bool */ private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ private $classMap = array(); + + /** @var bool */ private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ private $missingClasses = array(); + + /** @var ?string */ private $apcuPrefix; + /** + * @var self[] + */ + private static $registeredLoaders = array(); + + /** + * @param ?string $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + /** + * @return string[] + */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); } + /** + * @return array[] + * @psalm-return array> + */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } + /** + * @return array[] + * @psalm-return array + */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } + /** + * @return array[] + * @psalm-return array + */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } + /** + * @return string[] Array of classname => path + * @psalm-return array + */ public function getClassMap() { return $this->classMap; } /** - * @param array $classMap Class to filename map + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void */ public function addClassMap(array $classMap) { @@ -102,9 +175,11 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void */ public function add($prefix, $paths, $prepend = false) { @@ -147,11 +222,13 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException + * + * @return void */ public function addPsr4($prefix, $paths, $prepend = false) { @@ -195,8 +272,10 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void */ public function set($prefix, $paths) { @@ -211,10 +290,12 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException + * + * @return void */ public function setPsr4($prefix, $paths) { @@ -234,6 +315,8 @@ class ClassLoader * Turns on searching the include path for class files. * * @param bool $useIncludePath + * + * @return void */ public function setUseIncludePath($useIncludePath) { @@ -256,6 +339,8 @@ class ClassLoader * that have not been registered with the class map. * * @param bool $classMapAuthoritative + * + * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { @@ -276,6 +361,8 @@ class ClassLoader * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix + * + * @return void */ public function setApcuPrefix($apcuPrefix) { @@ -296,25 +383,44 @@ class ClassLoader * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } } /** * Unregisters this instance as an autoloader. + * + * @return void */ public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } } /** * Loads the given class or interface. * * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise + * @return true|null True if loaded, null otherwise */ public function loadClass($class) { @@ -323,6 +429,8 @@ class ClassLoader return true; } + + return null; } /** @@ -367,6 +475,21 @@ class ClassLoader return $file; } + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ private function findFileWithExtension($class, $ext) { // PSR-4 lookup @@ -438,6 +561,10 @@ class ClassLoader * Scope isolated include. * * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private */ function includeFile($file) { diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 00000000..d50e0c9f --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,350 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 3f795c8a..ef2b6e97 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'IPLib\\Address\\AddressInterface' => $vendorDir . '/mlocati/ip-lib/src/Address/AddressInterface.php', 'IPLib\\Address\\AssignedRange' => $vendorDir . '/mlocati/ip-lib/src/Address/AssignedRange.php', 'IPLib\\Address\\IPv4' => $vendorDir . '/mlocati/ip-lib/src/Address/IPv4.php', @@ -28,12 +29,49 @@ return array( 'Identicon\\Generator\\ImageMagickGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php', 'Identicon\\Generator\\SvgGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/SvgGenerator.php', 'Identicon\\Identicon' => $vendorDir . '/yzalis/identicon/src/Identicon/Identicon.php', + 'Jdenticon\\Canvas\\Canvas' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Canvas.php', + 'Jdenticon\\Canvas\\CanvasContext' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/CanvasContext.php', + 'Jdenticon\\Canvas\\ColorUtils' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/ColorUtils.php', + 'Jdenticon\\Canvas\\Matrix' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Matrix.php', + 'Jdenticon\\Canvas\\Png\\PngBuffer' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php', + 'Jdenticon\\Canvas\\Png\\PngEncoder' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php', + 'Jdenticon\\Canvas\\Png\\PngPalette' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php', + 'Jdenticon\\Canvas\\Point' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Point.php', + 'Jdenticon\\Canvas\\Rasterization\\Edge' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php', + 'Jdenticon\\Canvas\\Rasterization\\EdgeIntersection' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php', + 'Jdenticon\\Canvas\\Rasterization\\EdgeSuperSampleIntersection' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php', + 'Jdenticon\\Canvas\\Rasterization\\EdgeTable' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php', + 'Jdenticon\\Canvas\\Rasterization\\Layer' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php', + 'Jdenticon\\Canvas\\Rasterization\\LayerManager' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php', + 'Jdenticon\\Canvas\\Rasterization\\Rasterizer' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php', + 'Jdenticon\\Canvas\\Rasterization\\SuperSampleBuffer' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php', + 'Jdenticon\\Canvas\\Rasterization\\SuperSampleRange' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php', + 'Jdenticon\\Color' => $vendorDir . '/jdenticon/jdenticon/src/Color.php', + 'Jdenticon\\Identicon' => $vendorDir . '/jdenticon/jdenticon/src/Identicon.php', + 'Jdenticon\\IdenticonStyle' => $vendorDir . '/jdenticon/jdenticon/src/IdenticonStyle.php', + 'Jdenticon\\Rendering\\AbstractRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php', + 'Jdenticon\\Rendering\\ColorTheme' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/ColorTheme.php', + 'Jdenticon\\Rendering\\IconGenerator' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/IconGenerator.php', + 'Jdenticon\\Rendering\\ImagickRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php', + 'Jdenticon\\Rendering\\InternalPngRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php', + 'Jdenticon\\Rendering\\Point' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/Point.php', + 'Jdenticon\\Rendering\\Rectangle' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/Rectangle.php', + 'Jdenticon\\Rendering\\RendererInterface' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/RendererInterface.php', + 'Jdenticon\\Rendering\\SvgPath' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/SvgPath.php', + 'Jdenticon\\Rendering\\SvgRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/SvgRenderer.php', + 'Jdenticon\\Rendering\\Transform' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/Transform.php', + 'Jdenticon\\Rendering\\TriangleDirection' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/TriangleDirection.php', + 'Jdenticon\\Shapes\\Shape' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/Shape.php', + 'Jdenticon\\Shapes\\ShapeCategory' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapeCategory.php', + 'Jdenticon\\Shapes\\ShapeDefinitions' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php', + 'Jdenticon\\Shapes\\ShapePosition' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapePosition.php', 'PrivateBin\\Configuration' => $baseDir . '/lib/Configuration.php', 'PrivateBin\\Controller' => $baseDir . '/lib/Controller.php', 'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php', 'PrivateBin\\Data\\Database' => $baseDir . '/lib/Data/Database.php', 'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php', 'PrivateBin\\Data\\GoogleCloudStorage' => $baseDir . '/lib/Data/GoogleCloudStorage.php', + 'PrivateBin\\Data\\S3Storage' => $baseDir . '/lib/Data/S3Storage.php', 'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php', 'PrivateBin\\FormatV2' => $baseDir . '/lib/FormatV2.php', 'PrivateBin\\I18n' => $baseDir . '/lib/I18n.php', @@ -49,4 +87,5 @@ return array( 'PrivateBin\\Request' => $baseDir . '/lib/Request.php', 'PrivateBin\\View' => $baseDir . '/lib/View.php', 'PrivateBin\\Vizhash16x16' => $baseDir . '/lib/Vizhash16x16.php', + 'PrivateBin\\YourlsProxy' => $baseDir . '/lib/YourlsProxy.php', ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 9bd3702d..cf4579fa 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir); return array( 'PrivateBin\\' => array($baseDir . '/lib'), + 'Jdenticon\\' => array($vendorDir . '/jdenticon/jdenticon/src'), 'Identicon\\' => array($vendorDir . '/yzalis/identicon/src/Identicon'), 'IPLib\\' => array($vendorDir . '/mlocati/ip-lib/src'), ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 7a6fd4c0..5b03524d 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -22,13 +22,15 @@ class ComposerAutoloaderInitDontChange return self::$loader; } + require __DIR__ . '/platform_check.php'; + spl_autoload_register(array('ComposerAutoloaderInitDontChange', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInitDontChange', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; + require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInitDontChange::getInitializer($loader)); } else { @@ -63,11 +65,16 @@ class ComposerAutoloaderInitDontChange } } +/** + * @param string $fileIdentifier + * @param string $file + * @return void + */ function composerRequireDontChange($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - require $file; - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; } } diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index ab1f7d33..b03812eb 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -15,6 +15,10 @@ class ComposerStaticInitDontChange array ( 'PrivateBin\\' => 11, ), + 'J' => + array ( + 'Jdenticon\\' => 10, + ), 'I' => array ( 'Identicon\\' => 10, @@ -27,6 +31,10 @@ class ComposerStaticInitDontChange array ( 0 => __DIR__ . '/../..' . '/lib', ), + 'Jdenticon\\' => + array ( + 0 => __DIR__ . '/..' . '/jdenticon/jdenticon/src', + ), 'Identicon\\' => array ( 0 => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon', @@ -38,6 +46,7 @@ class ComposerStaticInitDontChange ); public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'IPLib\\Address\\AddressInterface' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AddressInterface.php', 'IPLib\\Address\\AssignedRange' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AssignedRange.php', 'IPLib\\Address\\IPv4' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/IPv4.php', @@ -60,12 +69,49 @@ class ComposerStaticInitDontChange 'Identicon\\Generator\\ImageMagickGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php', 'Identicon\\Generator\\SvgGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/SvgGenerator.php', 'Identicon\\Identicon' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Identicon.php', + 'Jdenticon\\Canvas\\Canvas' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Canvas.php', + 'Jdenticon\\Canvas\\CanvasContext' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/CanvasContext.php', + 'Jdenticon\\Canvas\\ColorUtils' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/ColorUtils.php', + 'Jdenticon\\Canvas\\Matrix' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Matrix.php', + 'Jdenticon\\Canvas\\Png\\PngBuffer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php', + 'Jdenticon\\Canvas\\Png\\PngEncoder' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php', + 'Jdenticon\\Canvas\\Png\\PngPalette' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php', + 'Jdenticon\\Canvas\\Point' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Point.php', + 'Jdenticon\\Canvas\\Rasterization\\Edge' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php', + 'Jdenticon\\Canvas\\Rasterization\\EdgeIntersection' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php', + 'Jdenticon\\Canvas\\Rasterization\\EdgeSuperSampleIntersection' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php', + 'Jdenticon\\Canvas\\Rasterization\\EdgeTable' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php', + 'Jdenticon\\Canvas\\Rasterization\\Layer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php', + 'Jdenticon\\Canvas\\Rasterization\\LayerManager' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php', + 'Jdenticon\\Canvas\\Rasterization\\Rasterizer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php', + 'Jdenticon\\Canvas\\Rasterization\\SuperSampleBuffer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php', + 'Jdenticon\\Canvas\\Rasterization\\SuperSampleRange' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php', + 'Jdenticon\\Color' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Color.php', + 'Jdenticon\\Identicon' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Identicon.php', + 'Jdenticon\\IdenticonStyle' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/IdenticonStyle.php', + 'Jdenticon\\Rendering\\AbstractRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php', + 'Jdenticon\\Rendering\\ColorTheme' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/ColorTheme.php', + 'Jdenticon\\Rendering\\IconGenerator' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/IconGenerator.php', + 'Jdenticon\\Rendering\\ImagickRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php', + 'Jdenticon\\Rendering\\InternalPngRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php', + 'Jdenticon\\Rendering\\Point' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/Point.php', + 'Jdenticon\\Rendering\\Rectangle' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/Rectangle.php', + 'Jdenticon\\Rendering\\RendererInterface' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/RendererInterface.php', + 'Jdenticon\\Rendering\\SvgPath' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/SvgPath.php', + 'Jdenticon\\Rendering\\SvgRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/SvgRenderer.php', + 'Jdenticon\\Rendering\\Transform' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/Transform.php', + 'Jdenticon\\Rendering\\TriangleDirection' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/TriangleDirection.php', + 'Jdenticon\\Shapes\\Shape' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/Shape.php', + 'Jdenticon\\Shapes\\ShapeCategory' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapeCategory.php', + 'Jdenticon\\Shapes\\ShapeDefinitions' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php', + 'Jdenticon\\Shapes\\ShapePosition' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapePosition.php', 'PrivateBin\\Configuration' => __DIR__ . '/../..' . '/lib/Configuration.php', 'PrivateBin\\Controller' => __DIR__ . '/../..' . '/lib/Controller.php', 'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php', 'PrivateBin\\Data\\Database' => __DIR__ . '/../..' . '/lib/Data/Database.php', 'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php', 'PrivateBin\\Data\\GoogleCloudStorage' => __DIR__ . '/../..' . '/lib/Data/GoogleCloudStorage.php', + 'PrivateBin\\Data\\S3Storage' => __DIR__ . '/../..' . '/lib/Data/S3Storage.php', 'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php', 'PrivateBin\\FormatV2' => __DIR__ . '/../..' . '/lib/FormatV2.php', 'PrivateBin\\I18n' => __DIR__ . '/../..' . '/lib/I18n.php', @@ -81,6 +127,7 @@ class ComposerStaticInitDontChange 'PrivateBin\\Request' => __DIR__ . '/../..' . '/lib/Request.php', 'PrivateBin\\View' => __DIR__ . '/../..' . '/lib/View.php', 'PrivateBin\\Vizhash16x16' => __DIR__ . '/../..' . '/lib/Vizhash16x16.php', + 'PrivateBin\\YourlsProxy' => __DIR__ . '/../..' . '/lib/YourlsProxy.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 00000000..9756660e --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,59 @@ + array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => '78aa70e3ab9277172489f9d88f8fd08cc1d03c97', + 'name' => 'privatebin/privatebin', + 'dev' => false, + ), + 'versions' => array( + 'jdenticon/jdenticon' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../jdenticon/jdenticon', + 'aliases' => array(), + 'reference' => '994ee07293fb978f983393ffcb2c0250592a6ac4', + 'dev_requirement' => false, + ), + 'mlocati/ip-lib' => array( + 'pretty_version' => '1.18.0', + 'version' => '1.18.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mlocati/ip-lib', + 'aliases' => array(), + 'reference' => 'c77bd0b1f3e3956c7e9661e75cb1f54ed67d95d2', + 'dev_requirement' => false, + ), + 'paragonie/random_compat' => array( + 'pretty_version' => 'v2.0.21', + 'version' => '2.0.21.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../paragonie/random_compat', + 'aliases' => array(), + 'reference' => '96c132c7f2f7bc3230723b66e89f8f150b29d5ae', + 'dev_requirement' => false, + ), + 'privatebin/privatebin' => array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => '78aa70e3ab9277172489f9d88f8fd08cc1d03c97', + 'dev_requirement' => false, + ), + 'yzalis/identicon' => array( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../yzalis/identicon', + 'aliases' => array(), + 'reference' => 'ff5ed090129cab9bfa2a322857d4a01d107aa0ae', + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 00000000..8b379f44 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 50600)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Canvas.php b/vendor/jdenticon/jdenticon/src/Canvas/Canvas.php new file mode 100644 index 00000000..6c5222f2 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Canvas.php @@ -0,0 +1,130 @@ +width = $width; + $this->height = $height; + $this->edges = new EdgeTable($width, $height); + } + + /** + * The width of the canvas in pixels. + * + * @var integer + */ + public $width = 0; + + /** + * The height of the canvas in pixels. + * + * @var integer + */ + public $height = 0; + + /** + * Specifies the background color. Allowed values are: + * - 32 bit integers on the format 0xRRGGBBAA + * - strings on the format #RGB + * - strings on the format #RRGGBB + * - strings on the format #RRGGBBAA + * + * @var integer|string + */ + public $backColor = 0x00000000; + + /** + * Gets a context used to draw polygons on this canvas. + * + * @returns \Jdenticon\Canvas\CanvasContext + */ + public function getContext() + { + return new CanvasContext($this, $this->edges); + } + + /** + * Renders the canvas as a PNG data stream. + * + * @param array $keywords Keywords to be written to the PNG stream. + * See https://www.w3.org/TR/PNG/#11keywords. + * @returns string + */ + public function toPng($keywords = array()) + { + $colorRanges = array(); + + Rasterizer::rasterize( + $colorRanges, $this->edges, + $this->width, $this->height); + + $backColor = ColorUtils::parse($this->backColor); + if (ColorUtils::alpha($backColor) > 0) { + $isColor = false; + + foreach ($colorRanges as & $value) { + if ($isColor) { + $value = ColorUtils::over($value, $backColor); + $isColor = false; + } else { + $isColor = true; + } + } + + unset($value); + } + + $palette = new PngPalette($colorRanges); + $png = new PngEncoder(); + + $png->writeImageHeader($this->width, $this->height, $palette->isValid ? + PngEncoder::INDEXED_COLOR : PngEncoder::TRUE_COLOR_WITH_ALPHA); + + $png->writeImageGamma(); + + foreach ($keywords as $key => $value) { + $png->writeTextualData($key, $value); + } + + if ($palette && $palette->isValid) { + $png->writePalette($palette); + $png->writeTransparency($palette); + $png->writeIndexed($colorRanges, $palette, + $this->width, $this->height); + } else { + $png->writeTrueColorWithAlpha($colorRanges, + $this->width, $this->height); + } + + $png->writeImageEnd(); + return $png->getBuffer(); + } +} \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php b/vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php new file mode 100644 index 00000000..9acfe5b1 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php @@ -0,0 +1,408 @@ +edges = $edges; + $this->canvas = $canvas; + $this->beginPath(); + $this->resetTransform(); + } + + /** + * Specifies the fill color that is used when the fill method is called. Allowed values are: + * - 32 bit integers on the format 0xRRGGBBAA + * - strings on the format #RGB + * - strings on the format #RRGGBB + * - strings on the format #RRGGBBAA + * + * @var integer|string + */ + public $fillStyle = 0x000000ff; + + /** + * Saves the current state to the state stack. + */ + public function save() + { + array_push($this->savedStates, array( + 'transform' => $this->transform, + 'fillStyle' => $this->fillStyle + )); + } + + /** + * Restores the last saved state of the CanvasContext. + */ + public function restore() + { + $state = array_pop($this->savedStates); + if ($state != NULL) { + $this->transform = $state['transform']; + $this->fillStyle = $state['fillStyle']; + } + } + + /** + * Resets the internal path buffer and begins a new path. + */ + public function resetTransform() + { + $this->transform = new Matrix(1, 0, 0, 1, 0, 0); + } + + /** + * Multiplies the current transformation matrix with the specified values. + */ + public function transform($a, $b, $c, $d, $e, $f) + { + if (gettype($a) != 'integer' || + gettype($b) != 'integer' || + gettype($c) != 'integer' || + gettype($d) != 'integer' || + gettype($e) != 'integer' || + gettype($f) != 'integer' + ) { + return; + } + + $this->transform = $this->transform->multiply($a, $b, $c, $d, $e, $f); + } + + /** + * Sets the transformation matrix to the specified matrix. + */ + public function setTransform($a, $b, $c, $d, $e, $f) + { + if (gettype($a) != 'integer' || + gettype($b) != 'integer' || + gettype($c) != 'integer' || + gettype($d) != 'integer' || + gettype($e) != 'integer' || + gettype($f) != 'integer' + ) { + return; + } + + $this->transform = new Matrix($a, $b, $c, $d, $e, $f); + } + + /** + * Applies a translation transformation to the CanvasContext. + * + * @param float $x Distance to move in the horizontal direction in pixels. + * @param float $y Distance to move in the vertical direction in pixels. + */ + public function translate($x, $y) + { + $this->transform = $this->transform->translate($x, $y); + } + + /** + * Applies a scale transformation to the CanvasContext. + * + * @param float $x Scale in the horizontal direction. 1 means no scale. + * @param float $y Scale in the vertical direction. 1 means no scale. + */ + public function scale($x, $y) + { + $this->transform = $this->transform->scale($x, $y); + } + + /** + * Applies a rotation transformation to the canvas around its current origo. + * + * @param float $angle Angle in radians measured clockwise from the + * positive x axis. + */ + public function rotate($angle) + { + $this->transform = $this->transform->rotate($angle); + } + + /** + * Removes all existing subpaths and begins a new path. + */ + public function beginPath() + { + $this->paths = array(); + } + + /** + * Starts a new subpath that begins in the same point as the start and end + * point of the previous one. + */ + public function closePath() + { + $pathsCount = count($this->paths); + if ($pathsCount > 0) { + $path = $this->paths[$pathsCount - 1]; + $pathCount = count($path); + + if ($pathCount > 2) { + // Close path + if ($path[0] != $path[$pathCount - 2] || + $path[1] != $path[$pathCount - 1] + ) { + $path[] = $path[0]; + $path[] = $path[1]; + } + + // Begin a new path + $this->paths[] = array($path[0], $path[1]); + } + } + } + + /** + * Begins a new subpath by moving the cursor to the specified position. + * + * @param float $x X coordinate. + * @param float $y Y coordinate. + */ + public function moveTo($x, $y) + { + $p = $this->transform->multiplyPoint($x, $y); + $this->paths[] = array($p->x, $p->y); + } + + /** + * Inserts an edge between the last and specified position. + * + * @param float $x Target X coordinate. + * @param float $y Target Y coordinate. + * @public + */ + public function lineTo($x, $y) + { + $pathsCount = count($this->paths); + if ($pathsCount == 0) { + $this->paths[] = array(); + $pathsCount++; + } + + $p = $this->transform->multiplyPoint($x, $y); + $path = &$this->paths[$pathsCount - 1]; + $path[] = $p->x; + $path[] = $p->y; + } + + /** + * Adds an arc to the current path. + * + * @param float $x X coordinate of the center of the arc. + * @param float $y Y coordinate of the center of the arc. + * @param float $radius Radius of the arc. + * @param float $startAngle The angle in radians at which the arc starts, + * measured clockwise from the positive x axis. + * @param float $endAngle The angle in radians at which the arc end, + * measured clockwise from the positive x axis. + * @param boolean $anticlockwise Specifies whether the arc will be drawn + * counter clockwise. Default is clockwise. + */ + public function arc($x, $y, $radius, $startAngle, $endAngle, $anticlockwise) + { + $TARGET_CHORD_LENGTH_PIXELS = 3; + + $sectors = floor((M_PI * $radius * 2) / $TARGET_CHORD_LENGTH_PIXELS); + if ($sectors < 9) { + $sectors = 9; + } + + $sectorAngle = M_PI * 2 / $sectors; + + if ($startAngle == $endAngle) { + return; + } + + if ($anticlockwise) { + $sectorAngle = -$sectorAngle; + + if ($startAngle - $endAngle >= M_PI * 2) { + $endAngle = $startAngle - M_PI * 2; + } else { + // Normalize end angle so that the sweep angle is in the range + // (0, -2PI] + $endAngle += + M_PI * 2 * ceil(($startAngle - $endAngle) / + (M_PI * 2) - 1); + } + } else { + if ($endAngle - $startAngle >= M_PI * 2) { + $endAngle = $startAngle + M_PI * 2; + } else { + // Normalize end angle so that the sweep angle is in the range + // (0, 2PI] + $endAngle -= + M_PI * 2 * ceil(($endAngle - $startAngle) / + (M_PI * 2) - 1); + } + } + + $dx; + $dy; + $sectors = ($endAngle - $startAngle) / $sectorAngle; + + $angle = $startAngle; + + for ($i = 0; $i < $sectors; $i++) { + $dx = cos($angle) * $radius; + $dy = sin($angle) * $radius; + $this->lineTo($x + $dx, $y + $dy); + $angle += $sectorAngle; + } + + $dx = cos($endAngle) * $radius; + $dy = sin($endAngle) * $radius; + $this->lineTo($x + $dx, $y + $dy); + } + + /** + * Fills the specified rectangle with fully transparent black without + * affecting the current paths. + * + * @param float $x X coordinate of the left side of the rectangle. + * @param float $y Y coordinate of the top of the rectangle. + * @param float $width Width of the rectangle. + * @param float $height Height of the rectangle. + */ + public function clearRect($x, $y, $width, $height) + { + $fullCanvas = false; + + if (!$this->transform->hasSkewing()) { + // Check if the whole canvas is cleared + $topLeft = $this->transform->multiplyPoint($x, $y); + if ($topLeft->x <= 0 && $topLeft->y <= 0) { + $bottomRight = $this->transform->multiplyPoint( + $x + $width, $y + $height); + if ($bottomRight->x >= $this->canvas->width && + $bottomRight->y >= $this->canvas->height + ) { + $fullCanvas = true; + } + } + } + + if ($fullCanvas) { + $this->edges->clear(); + } else { + $this->_fillRect(ColorUtils::FORCE_TRANSPARENT, + $x, $y, $width, $height); + } + } + + /** + * Fills the specified rectangle without affecting the current paths. + * + * @param float $x X coordinate of the left side of the rectangle. + * @param float $y Y coordinate of the top of the rectangle. + * @param float $width Width of the rectangle. + * @param float $height Height of the rectangle. + */ + public function fillRect($x, $y, $width, $height) + { + $fillColor = ColorUtils::parse($this->fillStyle); + $this->_fillRect($fillColor, $x, $y, $width, $height); + } + + private function _fillRect($fillColor, $x, $y, $width, $height) + { + $polygonId = $this->edges->getNextPolygonId(); + + $points = array( + $this->transform->multiplyPoint($x, $y), + $this->transform->multiplyPoint($x + $width, $y), + $this->transform->multiplyPoint($x + $width, $y + $height), + $this->transform->multiplyPoint($x, $y + $height), + $this->transform->multiplyPoint($x, $y) + ); + + $pointsCount = count($points); + for ($i = 1; $i < $pointsCount; $i++) { + $this->edges->add(new Edge( + $polygonId, + $points[$i - 1]->x, + $points[$i - 1]->y, + $points[$i]->x, + $points[$i]->y, + $fillColor)); + } + } + + /** + * Fills the defined paths. + * + * @param string $windingRule The winding rule to be used for determining + * which areas are covered by the current path. Valid values are + * "evenodd" and "nonzero". Default is "nonzero". + */ + public function fill($windingRule = "nonzero") + { + $polygonId = $this->edges->getNextPolygonId(); + $fillColor = ColorUtils::parse($this->fillStyle); + + foreach ($this->paths as $points) { + $pointsCount = count($points); + if ($pointsCount <= 2) { + // Nothing to fill + continue; + } + + for ($i = 2; $i < $pointsCount; $i += 2) { + $this->edges->add(new Edge( + $polygonId, + $points[$i - 2], + $points[$i - 1], + $points[$i], + $points[$i + 1], + $fillColor, + $windingRule)); + } + + // Close path + if ($points[0] != $points[$pointsCount - 2] || + $points[1] != $points[$pointsCount - 1] + ) { + $this->edges->add(new Edge( + $polygonId, + $points[$pointsCount - 2], + $points[$pointsCount - 1], + $points[0], + $points[1], + $fillColor, + $windingRule)); + } + } + } +} diff --git a/vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php b/vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php new file mode 100644 index 00000000..7709027d --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php @@ -0,0 +1,228 @@ +> 24) & 0xff; + } + + /** + * Gets the green component of a color. + * + * @param integer $color 32-bit color value on the format 0xRRGGBBAA. + * @return integer Green component in the range [0, 255]. + */ + public static function green($color) + { + return ($color >> 16) & 0xff; + } + + /** + * Gets the blue component of a color. + * + * @param integer $color 32-bit color value on the format 0xRRGGBBAA. + * @return integer Blue component in the range [0, 255]. + */ + public static function blue($color) + { + return ($color >> 8) & 0xff; + } + + /** + * Formats a color as a string. + * + * @param integer $color Color to format. + * @return string + */ + public static function format($color) + { + return bin2hex(pack('N', $color)); + } + + /** + * Computes a mix of the two specified colors, with the proportion given + * by the specified weight. + * + * @param integer $color1 First color to mix. + * @param integer $color2 Second color to mix. + * @param float $weight Weight in the range [0,1]. + * 0 gives $color1, 1 gives $color2. + * @return integer Mixed color. + */ + public static function mix($color1, $color2, $weight) + { + if ($weight < 0) { + $weight = 0; + } elseif ($weight > 1) { + $weight = 1; + } + + $a = ($color1 & 0xff) * (1 - $weight) + ($color2 & 0xff) * $weight; + if ($a <= 0.1) { + return 0; + } + + $r = ( + ($color1 >> 24) * ($color1 & 0xff) * (1 - $weight) + + ($color2 >> 24) * ($color2 & 0xff) * $weight + ) / $a; + + $g = ( + (($color1 >> 16) & 0xff) * ($color1 & 0xff) * (1 - $weight) + + (($color2 >> 16) & 0xff) * ($color2 & 0xff) * $weight + ) / $a; + + $b = ( + (($color1 >> 8) & 0xff) * ($color1 & 0xff) * (1 - $weight) + + (($color2 >> 8) & 0xff) * ($color2 & 0xff) * $weight + ) / $a; + + if ($a > 255) $a = 255; + if ($r > 255) $r = 255; + if ($g > 255) $g = 255; + if ($b > 255) $b = 255; + + return ((int)$r << 24) | ((int)$g << 16) | ((int)$b << 8) | (int)$a; + } + + /** + * Parses a value to a 32-bit color on the format 0xRRGGBBAA. + * + * @param integer|string $color The value to parse. + * @return integer + */ + public static function parse($color) + { + if (gettype($color) == "integer") { + return $color & 0xffffffff; + } + + $color = "$color"; + + if (preg_match('/^#?[0-9a-fA-F]+$/', $color)) { + $hexColor = $color; + if ($hexColor[0] == '#') { + $hexColor = substr($hexColor, 1); + } + + switch (strlen($hexColor)) { + case 3: + $numeric = intval($hexColor, 16); + return ( + (($numeric & 0xf00) << 20) | + (($numeric & 0xf00) << 16) | + (($numeric & 0x0f0) << 16) | + (($numeric & 0x0f0) << 12) | + (($numeric & 0x00f) << 12) | + (($numeric & 0x00f) << 8) | + 0xff); + case 6: + return (intval($hexColor, 16) << 8) | 0xff; + case 8: + // Workaround to cope with PHP limitation of intval + $numeric = + (intval(substr($hexColor, 0, 4), 16) << 16) | + (intval(substr($hexColor, 4, 4), 16)); + return $numeric; + } + } + + throw new \InvalidArgumentException("Invalid color '$color'."); + } + + /** + * Blends this color with another color using the over blending operation. + * + * @param integer $fore The foreground color. + * @param integer $back The background color. + * @return integer + */ + public static function over($fore, $back) + { + $foreA = ($fore & 0xff); + $backA = ($back & 0xff); + + if ($foreA < 1) { + return $back; + } elseif ($foreA > 254 || $backA < 1) { + return $fore; + } + + // Source: + // https://en.wikipedia.org/wiki/Alpha_compositing#Description + $forePA = $foreA * 255; + $backPA = $backA * (255 - $foreA); + $pa = ($forePA + $backPA); + + $b = (int) ( + ($forePA * (($fore >> 8) & 0xff) + $backPA * (($back >> 8) & 0xff)) / + $pa); + + $g = (int) ( + ($forePA * (($fore >> 16) & 0xff) + $backPA * (($back >> 16) & 0xff)) / + $pa); + + $r = (int) ( + ($forePA * (($fore >> 24) & 0xff) + $backPA * (($back >> 24) & 0xff)) / + $pa); + + $a = (int) ($pa / 255); + + return ($r << 24) | ($g << 16) | ($b << 8) | $a; + } +}; + diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Matrix.php b/vendor/jdenticon/jdenticon/src/Canvas/Matrix.php new file mode 100644 index 00000000..9ce00dcb --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Matrix.php @@ -0,0 +1,141 @@ +a = $a; + $this->b = $b; + $this->c = $c; + $this->d = $d; + $this->e = $e; + $this->f = $f; + } + + /** + * Gets a value determining if this matrix has skewing values. + * + * @return boolean + */ + public function hasSkewing() + { + return $this->b || $this->c; + } + + /** + * Gets a value determining if this matrix has translation values. + * + * @return boolean + */ + public function hasTranslation() + { + return $this->e || $this->f; + } + + /** + * Gets a value determining if this matrix has scaling values. + * + * @return boolean + */ + public function hasScaling() + { + return $this->a != 1 || $this->d != 1; + } + + /** + * Returns a new matrix based on the current matrix multiplied with the + * specified matrix values. + * + * @return \Jdenticon\Canvas\Matrix + */ + public function multiply($a, $b, $c, $d, $e, $f) + { + return new Matrix( + $this->a * $a + $this->c * $b, + $this->b * $a + $this->d * $b, + $this->a * $c + $this->c * $d, + $this->b * $c + $this->d * $d, + $this->a * $e + $this->c * $f + $this->e, + $this->b * $e + $this->d * $f + $this->f + ); + } + + /** + * Multiplies the specified point with the current matrix and returns the + * resulting point. + * + * @param float $x X coordinate. + * @param float $y Y coordinate. + * @return \Jdenticon\Canvas\Point + */ + public function multiplyPoint($x, $y) + { + return new Point( + $this->a * $x + $this->c * $y + $this->e, + $this->b * $x + $this->d * $y + $this->f + ); + } + + /** + * Returns a new matrix based on the current matrix with a rotation + * transformation applied. + * + * @param float $angle Rotation angle in radians. + * @return \Jdenticon\Canvas\Matrix + */ + public function rotate($angle) + { + $sin = sin($angle); + $cos = cos($angle); + return $this->multiply($cos, $sin, -$sin, $cos, 0, 0); + } + + /** + * Returns a new matrix based on the current matrix with a translation + * transformation applied. + * + * @param float $x Horizontal move distance. + * @param float $y Vertical move distance. + * @return \Jdenticon\Canvas\Matrix + */ + public function translate($x, $y) + { + return $this->multiply(1, 0, 0, 1, $x, $y); + } + + /** + * Returns a new matrix based on the current matrix with a scaling + * transformation applied. + * + * @param float $x Horizontal scale. + * @param float $y Vertical scale. + * @return \Jdenticon\Canvas\Matrix + */ + public function scale($x, $y) + { + return $this->multiply($x, 0, 0, $y, 0, 0); + } +} \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php new file mode 100644 index 00000000..78a90ba5 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php @@ -0,0 +1,92 @@ +buffer .= $str; + } + + /** + * Writes a 32 bit unsigned int to the buffer in Big Endian format. + * + * @param integer $value Value to write. + */ + public function writeUInt32BE($value) + { + $this->buffer .= pack('N', $value); + } + + /** + * Writes an 8 bit unsigned int to the buffer. + * + * @param integer $value Value to write. + */ + public function writeUInt8($value) + { + $this->buffer .= pack('C', $value); + } + + /** + * Starts a new PNG chunk. + * + * @param string $type Name of the chunk. Must contain exactly 4 + * ASCII characters. + */ + public function startChunk($type) + { + $this->chunkPreviousBuffer = $this->buffer; + $this->buffer = $type; + } + + /** + * Closes the current PNG chunk. + */ + public function endChunk() + { + // Compute Crc32 for type + data + $data = $this->buffer; + $crc = crc32($data); + + $this->buffer = + $this->chunkPreviousBuffer . + + // Length + pack('N', strlen($data) - 4) . + + // Content + $data . + + // Crc32 + pack('N', $crc); + } + + /** + * Gets a string containing the PNG encoded data. + * + * @return string + */ + public function getBuffer() + { + return $this->buffer; + } +} diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php new file mode 100644 index 00000000..5927e704 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php @@ -0,0 +1,238 @@ +buffer = new PngBuffer(); + $this->buffer->writeString("\x89\x50\x4e\x47\xd\xa\x1a\xa"); + } + + /** + * Writes an IHDR chunk to the png data stream. + * + * @param int $width Image width in pixels. + * @param int $height Image height in pixels. + * @param int $colorType Color depth, speocfy one of the constants in + * PngEncoder. + */ + public function writeImageHeader($width, $height, $colorType) + { + $this->buffer->startChunk("IHDR"); + $this->buffer->writeUInt32BE($width); + $this->buffer->writeUInt32BE($height); + $this->buffer->writeUInt8(8); // Bit depth + $this->buffer->writeUInt8($colorType); + $this->buffer->writeUInt8(0); // Compression + $this->buffer->writeUInt8(0); // Filter + $this->buffer->writeUInt8(0); // Interlace + $this->buffer->endChunk(); + } + + /** + * Writes a gAMA chunk to the png data stream. + * + * @param int $gamma Gamma value. + */ + public function writeImageGamma($gamma = 45455) + { + $this->buffer->startChunk("gAMA"); + $this->buffer->writeUInt32BE($gamma); + $this->buffer->endChunk(); + } + + /** + * Writes an IDAT chunk of truecolor encoded image data. + * + * @param array $colorRanges Image data on the format + * array(count0, color0, count1, color1, ...) + * @param int $width Image width in pixels. + * @param int $height Image height in pixels. + */ + public function writeTrueColorWithAlpha( + array & $colorRanges, $width, $height) + { + $this->buffer->startChunk("IDAT"); + + $uncompressed = ''; + $count = -1; + $x = 0; + + foreach ($colorRanges as $value) { + if ($count === -1) { + $count = $value; + } else { + if ($count !== 0) { + if ($x === $width) { + $x = 0; + } + if ($x === 0) { + $uncompressed .= pack('C', 0); // No filtering + } + + $uncompressed .= str_repeat(pack('N', $value), $count); + $x += $count; + } + + $count = -1; + } + } + + $compressed = gzcompress($uncompressed, 2); + $this->buffer->writeString($compressed); + + $this->buffer->endChunk(); + } + + /** + * Writes an IDAT chunk of indexed image data. + * + * @param array $colorRanges Image data on the format + * array(count0, color0, count1, color1, ...) + * @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the + * indexed colors. + * @param int $width Image width in pixels. + * @param int $height Image height in pixels. + */ + public function writeIndexed( + array & $colorRanges, + PngPalette $palette, + $width, $height) + { + $this->buffer->startChunk("IDAT"); + + $uncompressed = ''; + + $count = -1; + $x = 0; + + foreach ($colorRanges as $value) { + if ($count === -1) { + $count = $value; + } else { + if ($count !== 0) { + if ($x === $width) { + $x = 0; + } + if ($x === 0) { + $uncompressed .= pack('C', 0); // No filtering + } + + $colorIndex = $palette->lookup[$value]; + $uncompressed .= str_repeat(pack('C', $colorIndex), $count); + $x += $count; + } + + $count = -1; + } + } + + $compressed = gzcompress($uncompressed, 2); + $this->buffer->writeString($compressed); + + $this->buffer->endChunk(); + } + + /** + * Writes a PLTE chunk containing the indexed colors. + * + * @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the + * indexed colors. + */ + public function writePalette(PngPalette $palette) + { + if ($palette && $palette->isValid) { + $this->buffer->startChunk("PLTE"); + + foreach ($palette->colors as $color) { + $this->buffer->writeString( + pack('C', ($color >> 24) & 0xff) . + pack('C', ($color >> 16) & 0xff) . + pack('C', ($color >> 8) & 0xff)); + } + + $this->buffer->endChunk(); + } + } + + /** + * Writes a tRNS chunk containing the alpha values of indexed colors. + * + * @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the + * indexed colors. + */ + public function writeTransparency(PngPalette $palette) + { + if ($palette && $palette->isValid && $palette->hasAlphaChannel) { + $this->buffer->startChunk("tRNS"); + + $alpha = ''; + + foreach ($palette->colors as $color) { + $alpha .= pack('C', $color & 0xff); + } + + $this->buffer->writeString($alpha); + + $this->buffer->endChunk(); + } + } + + /** + * Writes a tEXt chunk containing the specified strings. + * + * @param string $key Key, one of + * {@link https://www.w3.org/TR/2003/REC-PNG-20031110/#11keywords} + * @param string $value Value. + */ + public function writeTextualData($key, $value) + { + $this->buffer->startChunk("tEXt"); + $this->buffer->writeString($key); + $this->buffer->writeUInt8(0); + $this->buffer->writeString($value); + $this->buffer->endChunk(); + } + + /** + * Writes an IEND chunk to the png data stream. + */ + public function writeImageEnd() + { + $this->buffer->startChunk("IEND"); + $this->buffer->endChunk(); + } + + /** + * Gets a binary string containing the PNG data. + * + * @return string + */ + public function getBuffer() + { + return $this->buffer->getBuffer(); + } +} diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php new file mode 100644 index 00000000..37887b65 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php @@ -0,0 +1,92 @@ + 0 && !isset($lookup[$value])) { + if (!$hasAlphaChannel && ($value & 0xff) < 255) { + $hasAlphaChannel = true; + } + + $lookup[$value] = $colorsCount++; + $colors[] = $value; + + if ($colorsCount > 256) { + break; + } + } + + $count = -1; + } + } + + $this->hasAlphaChannel = $hasAlphaChannel; + $this->colors = & $colors; + $this->lookup = & $lookup; + $this->isValid = $colorsCount <= 256; + } + + /** + * Specifies if the palette is valid to be used for encoding a PNG image. + * + * @var boolean + */ + public $isValid; + + /** + * Specifies if the palette has any partial or fully transparent + * colors. + * + * @var boolean + */ + public $hasAlphaChannel; + + /** + * Array of colors in the palette. + * + * @var array + */ + public $colors; + + /** + * Lookup table from 32-bit color value to color index. + * + * @var array + */ + public $lookup; +} diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Point.php b/vendor/jdenticon/jdenticon/src/Canvas/Point.php new file mode 100644 index 00000000..0c73133f --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Point.php @@ -0,0 +1,41 @@ +x = $x; + $this->y = $y; + } +} \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php new file mode 100644 index 00000000..d554b91d --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php @@ -0,0 +1,44 @@ +polygonId = $polygonId; + $this->x0 = $x0; + $this->x1 = $x1; + $this->y0 = $y0; + $this->y1 = $y1; + $this->color = $color; + $this->windingRule = $windingRule; + } + + public function intersection($y) + { + $dx = + ($this->x1 - $this->x0) * ($this->y0 - $y) / + ($this->y0 - $this->y1); + return $this->x0 + $dx; + } +} + diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php new file mode 100644 index 00000000..59f0ef37 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php @@ -0,0 +1,27 @@ +fromX = $fromX; + $this->width = $width; + $this->edge = $edge; + } +} + diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php new file mode 100644 index 00000000..b88a2711 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php @@ -0,0 +1,24 @@ +x = $x; + $this->edge = $edge; + } +} \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php new file mode 100644 index 00000000..6a67f505 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php @@ -0,0 +1,158 @@ +width = $width; + $this->height = $height; + $this->clear(); + } + + /** + * Sorts the edges of each scanline in ascending x coordinates. + */ + public function clear() + { + $this->scanlines = array(); + $this->nextPolygonId = 1; + } + + /** + * Gets an id for the next polygon. + * + * @return int + */ + public function getNextPolygonId() + { + return $this->nextPolygonId++; + } + + /** + * Gets the scaline for the specified Y coordinate, or NULL if there are + * no edges for the specified Y coordinate. + * + * @return array|null. + */ + public function getScanline($y) + { + return isset($this->scanlines[$y]) ? $this->scanlines[$y] : null; + } + + /** + * Adds an edge to the table. + * + * @param \Jdenticon\Canvas\Rasterization\Edge $edge + */ + public function add(\Jdenticon\Canvas\Rasterization\Edge $edge) + { + $minY = 0; + $maxY = 0; + + if ($edge->y0 == $edge->y1) { + // Skip horizontal lines + return; + } elseif ($edge->y0 < $edge->y1) { + $minY = (int)($edge->y0); + $maxY = (int)($edge->y1 + 0.996 /* 1/255 */); + } else { + $minY = (int)($edge->y1); + $maxY = (int)($edge->y0 + 0.996 /* 1/255 */); + } + + if ($maxY < 0 || $minY >= $this->height) { + return; + } + + if ($minY < 0) { + $minY = 0; + } + if ($maxY > $this->height) { + $maxY = $this->height; + } + + if ($minY < $maxY) { + $y = $minY; + $x1 = $edge->intersection($y); + + while ($y < $maxY) { + $x2 = $edge->intersection($y + 1); + + $fromX; + $width; + if ($x1 < $x2) { + $fromX = (int)($x1); + $width = (int)($x2 + 0.9999) - $fromX; + } else { + $fromX = (int)($x2); + $width = (int)($x1 + 0.9999) - $fromX; + } + + if ($fromX < 0) { + $width += $fromX; + $fromX = 0; + + if ($width < 0) { + $width = 0; + } + } + + if ($fromX < $this->width) { + if (!isset($this->scanlines[$y])) { + $this->scanlines[$y] = array(); + } + + $this->scanlines[$y][] = new EdgeIntersection( + $fromX, $width, $edge); + } + + $x1 = $x2; + $y++; + } + } + } + + private static function edge_cmp($x, $y) + { + if ($x->fromX < $y->fromX) { + return -1; + } + if ($x->fromX > $y->fromX) { + return 1; + } + return 0; + } + + /** + * Sorts the edges of each scanline in ascending x coordinates. + */ + public function sort() + { + foreach ($this->scanlines as $i => &$scanline) { + usort($scanline, array( + 'Jdenticon\\Canvas\\Rasterization\\EdgeTable', 'edge_cmp')); + } + } +} \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php new file mode 100644 index 00000000..f3d83bf0 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php @@ -0,0 +1,30 @@ +polygonId = $polygonId; + $this->color = $color; + $this->winding = $winding; + $this->windingRule = $windingRule; + } +} diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php new file mode 100644 index 00000000..98592729 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php @@ -0,0 +1,150 @@ +color = ColorUtils::TRANSPARENT; + } + + /** + * Copies all layers in this manager to another LayerManager. + * + * @param \Jdenticon\Canvas\Rasterization\LayerManager $other The + * LayerManager to copy all layers to. + */ + public function copyTo(LayerManager $other) + { + $other->color = $this->color; + + $layer = $this->topLayer; + $previousCopy = null; + + while ($layer !== null) { + $copy = new Layer( + $layer->polygonId, + $layer->color, + $layer->winding, + $layer->windingRule + ); + + if ($previousCopy === null) { + $other->topLayer = $copy; + } + else { + $previousCopy->nextLayer = $copy; + } + + $previousCopy = $copy; + $layer = $layer->nextLayer; + } + } + + /** + * Adds a layer for the specified edge. The z-order is defined by its id. + * + * @param \Jdenticon\Canvas\Rasterization\Edge edge + */ + public function add(Edge $edge) + { + $dwinding = $edge->y0 < $edge->y1 ? 1 : -1; + + $layer = $this->topLayer; + $previousLayer = null; + + while ($layer !== null) { + if ($layer->polygonId === $edge->polygonId) { + $layer->winding += $dwinding; + + $inPath = $layer->windingRule == 'evenodd' ? + ($layer->winding % 2 === 1) : ($layer->winding !== 0); + + if (!$inPath) { + // Remove layer + if ($previousLayer === null) { + $this->topLayer = $layer->nextLayer; + } + else { + $previousLayer->nextLayer = $layer->nextLayer; + } + } + break; + } elseif ($layer->polygonId < $edge->polygonId) { + // Insert here + $newLayer = new Layer( + $edge->polygonId, + $edge->color, + $dwinding, + $edge->windingRule + ); + $newLayer->nextLayer = $layer; + + if ($previousLayer === null) { + $this->topLayer = $newLayer; + } else { + $previousLayer->nextLayer = $newLayer; + } + break; + } + + $previousLayer = $layer; + $layer = $layer->nextLayer; + } + + if ($layer === null) { + $newLayer = new Layer( + $edge->polygonId, + $edge->color, + $dwinding, + $edge->windingRule + ); + + if ($previousLayer === null) { + $this->topLayer = $newLayer; + } else { + $previousLayer->nextLayer = $newLayer; + } + } + + // Update current color + $color = ColorUtils::TRANSPARENT; + $layer = $this->topLayer; + + while ($layer !== null && ($color & 0xff) < 255) { + if ($layer->color === ColorUtils::FORCE_TRANSPARENT) { + break; + } + + $color = ColorUtils::over($layer->color, $color); + } + + $this->color = $color; + } +} diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php new file mode 100644 index 00000000..0a5269af --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php @@ -0,0 +1,379 @@ +sort(); + + $superSampleBuffer = new SuperSampleBuffer( + $width, self::SAMPLES_PER_PIXEL_X); + + $layers = array(); + $color = 0; + + // Keeps track of how many of the subpixellayers that are used for + // the currently rendered scanline. Until a range requiring + // supersampling is encountered only a single layer is needed. + $usedLayers = 0; + + for ($i = 0; $i < self::SAMPLES_PER_PIXEL_Y; $i++) { + $layers[] = new LayerManager(); + } + + for ($ey = 0; $ey < $height; $ey++) { + $scanline = $edgeTable->getScanline($ey); + if ($scanline === null) { + $colorData[] = $width; + $colorData[] = 0; + continue; + } + + $superSampleRanges = self::getSuperSampleRanges($scanline, $width); + $superSampleRangeCount = count($superSampleRanges); + + foreach ($layers as $layer) { + $layer->topLayer = null; + $layer->color = ColorUtils::TRANSPARENT; + } + + $usedLayers = 1; + + if ($superSampleRanges[0]->fromX) { + $colorData[] = $superSampleRanges[0]->fromX; + $colorData[] = 0; + } + + for ( + $rangeIndex = 0; + $rangeIndex < $superSampleRangeCount; + $rangeIndex++ + ) { + $superSampleRange = $superSampleRanges[$rangeIndex]; + $edge = $superSampleRange->edges[0]; + + // If there is exactly one edge in the supersample range, and it + // is crossing the entire scanline, we can perform the + // antialiasing by integrating the edge function. + if (!isset($superSampleRange->edges[1]) && ( + $edge->y0 <= $ey && $edge->y1 >= $ey + 1 || + $edge->y0 >= $ey + 1 && $edge->y1 <= $ey + )) { + // Determine the lower and upper x value where the edge + // intersects the scanline. + $xey = $edge->intersection($ey); + $xey1 = $edge->intersection($ey + 1); + + if ($xey < $xey1) { + $x0 = $xey; + $x1 = $xey1; + } else { + $x0 = $xey1; + $x1 = $xey; + } + + $rangeWidth = $x1 - $x0; + + if ($usedLayers === 1) { + $subScanlineLayers = $layers[0]; + $fromColor = $subScanlineLayers->color; + $subScanlineLayers->add($edge); + $toColor = $subScanlineLayers->color; + } else { + $fromColorR = 0; + $fromColorG = 0; + $fromColorB = 0; + $fromColorA = 0; + $toColorR = 0; + $toColorG = 0; + $toColorB = 0; + $toColorA = 0; + + // Compute the average color of all subpixel layers + // before and after the edge intersection. + // The calculation is inlined for increased performance. + for ($i = 0; $i < $usedLayers; $i++) { + $subScanlineLayers = $layers[$i]; + + // Add to average from-color + $color = $subScanlineLayers->color; + $alpha = $color & 0xff; + if ($alpha > 0) { + $fromColorA += $alpha; + $fromColorR += (($color >> 24) & 0xff) * $alpha; + $fromColorG += (($color >> 16) & 0xff) * $alpha; + $fromColorB += (($color >> 8) & 0xff) * $alpha; + } + + // Add the new layer + $subScanlineLayers->add($edge); + + // Add to average to-color + $color = $subScanlineLayers->color; + $alpha = $color & 0xff; + if ($alpha > 0) { + $toColorA += $alpha; + $toColorR += (($color >> 24) & 0xff) * $alpha; + $toColorG += (($color >> 16) & 0xff) * $alpha; + $toColorB += (($color >> 8) & 0xff) * $alpha; + } + } + + $fromColor = $fromColorA === 0 ? 0 : ColorUtils::from( + (int)($fromColorA / $usedLayers), + (int)($fromColorR / $fromColorA), + (int)($fromColorG / $fromColorA), + (int)($fromColorB / $fromColorA)); + + $toColor = $toColorA === 0 ? 0 : ColorUtils::from( + (int)($toColorA / $usedLayers), + (int)($toColorR / $toColorA), + (int)($toColorG / $toColorA), + (int)($toColorB / $toColorA)); + } + + // Render pixels + for ( + $x = $superSampleRange->fromX; + $x < $superSampleRange->toXExcl; + $x++ + ) { + if ($x0 >= $x + 1) { + // Pixel not covered + $colorData[] = 1; + $colorData[] = $fromColor; + continue; + } + + if ($x1 <= $x) { + // Pixel fully covered + $colorData[] = 1; + $colorData[] = $toColor; + continue; + } + + // toColor coverage in the range [0.0, 1.0] + // Initialize to the fully covered range of the pixel. + $coverage = $x1 < $x + 1 ? $x + 1 - $x1 : 0; + + // Compute integral for non-vertical edges + if ($rangeWidth > 0.001) { + // Range to integrate + $integralFrom = $x0 > $x ? $x0 : $x;; + $integralTo = $x1 < $x + 1 ? $x1 : $x + 1; + + $coverage += + ( + ( + $integralTo * $integralTo - + $integralFrom * $integralFrom + ) / 2 + + $x0 * ($integralFrom - $integralTo) + ) / $rangeWidth; + } + + $colorData[] = 1; + $colorData[] = ColorUtils::mix( + $fromColor, $toColor, $coverage); + } + + $color = $toColor; + + } // /simplified antialiasing + else { + // Super sampling + $y = $ey + self::SAMPLE_HEIGHT / 2; + + // Ensure all subpixel layers are initialized + while ($usedLayers < self::SAMPLES_PER_PIXEL_Y) { + $layers[0]->copyTo($layers[$usedLayers]); + $usedLayers++; + } + + foreach ($layers as $subScanlineLayers) { + $color = $subScanlineLayers->color; + + $intersections = self::getIntersections( + $superSampleRange->edges, $y); + + foreach ($intersections as $intersection) { + $superSampleBuffer->add($color, + $intersection->x - $superSampleRange->fromX); + $subScanlineLayers->add($intersection->edge); + $color = $subScanlineLayers->color; + } + + $superSampleBuffer->add( + $color, $superSampleRange->width + 1); + $superSampleBuffer->rewind(); + + $y += self::SAMPLE_HEIGHT; + } // /subpixel + + // Blend subpixels + $color = $superSampleBuffer->colorAt( + $superSampleRange->width); + $superSampleBuffer->emptyTo( + $colorData, $superSampleRange->width); + + //$color = end($colorData); + } // /super sampling + + // Forward last color + if ($rangeIndex + 1 < $superSampleRangeCount) { + $count = + $superSampleRanges[$rangeIndex + 1]->fromX - + $superSampleRange->toXExcl; + + if ($count > 0) { + $colorData[] = $count; + $colorData[] = $color; + } + } else { + $count = $width - $superSampleRange->toXExcl; + if ($count > 0) { + $colorData[] = $count; + $colorData[] = $color; + } + } + } // /range + } + + return $colorData; + } + + private static function intersection_cmp($a, $b) + { + if ($a->x < $b->x) { + return -1; + } + + if ($a->x > $b->x) { + return 1; + } + + return 0; + } + + /** + * Determines what edges that intersect a horizontal line with the specified + * y coordinate. For each intersecting edge the intersecting x coordinate is + * returned. + * + * @param array $edges Array of edges in the current scanline. + * @param int $y Y coordinate of the current scanline. + * @return array Array containing EdgeSuperSampleIntersection. Objects + * are sorted ascending by x coordinate. + */ + private static function getIntersections($edges, $y) + { + $intersections = array(); + + foreach ($edges as $edge) { + if ($edge->y0 < $y && $edge->y1 >= $y || + $edge->y0 >= $y && $edge->y1 < $y + ) { + $x = $edge->x0 + + ($edge->x1 - $edge->x0) * ($y - $edge->y0) / + ($edge->y1 - $edge->y0); + + $intersections[] = new EdgeSuperSampleIntersection($x, $edge); + } + } + + usort($intersections, array( + 'Jdenticon\\Canvas\\Rasterization\\Rasterizer', + 'intersection_cmp')); + + return $intersections; + } + + /** + * Determines what ranges of a scanline that needs to be supersampled. + * + * @param array $scanline Array of edges in the current scanline. + * @return array Array of SuperSampleRange. + */ + private static function getSuperSampleRanges(&$scanline, $width) + { + $superSampleRanges = array(); + + $rangeIndex = 0; + $scanlineCount = count($scanline); + + while ($rangeIndex < $scanlineCount) { + $range = $scanline[$rangeIndex]; + + if ($range->fromX >= $width) { + break; + } + + $superSampleRange = new SuperSampleRange( + $range->fromX, + $range->fromX + $range->width + ); + $superSampleRange->edges[] = $range->edge; + + $rangeIndex++; + + for ($i = $rangeIndex; $i < $scanlineCount; $i++) { + $range = $scanline[$i]; + + if ($range->fromX < $superSampleRange->toXExcl) { + $superSampleRange->toXExcl = max( + $superSampleRange->toXExcl, + $range->fromX + $range->width); + $superSampleRange->edges[] = $range->edge; + $rangeIndex++; + } else { + break; + } + } + + $superSampleRange->toXExcl = min($superSampleRange->toXExcl, $width); + $superSampleRange->width = + $superSampleRange->toXExcl - $superSampleRange->fromX; + + $superSampleRanges[] = $superSampleRange; + } + + return $superSampleRanges; + } +} + diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php new file mode 100644 index 00000000..82860e2e --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php @@ -0,0 +1,198 @@ +samples = array(); + $this->samplesPerPixel = $samplesPerPixel; + + $this->pixelOffset = 0; + $this->subPixelOffset = 0; + + $this->width = $width; + $this->used = -1; + } + + /** + * Rewinds the cursor to the beginning of the buffer. + */ + public function rewind() + { + $this->pixelOffset = 0; + $this->subPixelOffset = 0; + } + + /** + * Clears the samples in this buffer. + */ + public function clear() + { + $this->pixelOffset = 0; + $this->subPixelOffset = 0; + $this->used = -1; + } + + /** + * Writes the average color of each pixel to a specified color array. + * + * @param array $colorData The average colors will be written to this + * color array. + * @param integer $count Number of pixels to write. + */ + public function emptyTo(& $colorData, $count) + { + for ($i = 0; $i < $count; $i++) { + $sampleCount = $this->samples[$i * 5 + self::IDX_COUNT]; + $a = $this->samples[$i * 5 + self::IDX_A]; + $color = $sampleCount == 0 || $a == 0 ? 0 : + ColorUtils::from( + (int)($a / $sampleCount), + (int)($this->samples[$i * 5 + self::IDX_R] / $a), + (int)($this->samples[$i * 5 + self::IDX_G] / $a), + (int)($this->samples[$i * 5 + self::IDX_B] / $a) + ); + + $colorData[] = 1; + $colorData[] = $color; + } + + $this->pixelOffset = 0; + $this->subPixelOffset = 0; + $this->used = -1; + } + + /** + * Gets the average color of the pixel at a specified index. + * + * @param integer $index The index of the pixel. + * @return integer + */ + public function colorAt($index) + { + $sampleCount = $this->samples[$index * 5 + self::IDX_COUNT]; + $alphaSum = $this->samples[$index * 5 + self::IDX_A]; + return $sampleCount == 0 || $alphaSum == 0 ? 0 : + ColorUtils::from( + (int)($alphaSum / $sampleCount), + (int)($this->samples[$index * 5 + self::IDX_R] / $alphaSum), + (int)($this->samples[$index * 5 + self::IDX_G] / $alphaSum), + (int)($this->samples[$index * 5 + self::IDX_B] / $alphaSum) + ); + } + + /** + * Adds a color to the current pixel in the buffer. + * + * @param integer $count Number of samples of the color to be added to + * the buffer. + */ + private function _add($count, $a, $r, $g, $b) + { + if ($this->used < $this->pixelOffset) { + $this->used = $this->pixelOffset; + + $this->samples[$this->pixelOffset * 5 + self::IDX_COUNT] = $count; + $this->samples[$this->pixelOffset * 5 + self::IDX_A] = $a * $count; + $this->samples[$this->pixelOffset * 5 + self::IDX_R] = $a * $r * $count; + $this->samples[$this->pixelOffset * 5 + self::IDX_G] = $a * $g * $count; + $this->samples[$this->pixelOffset * 5 + self::IDX_B] = $a * $b * $count; + } else { + $this->samples[$this->pixelOffset * 5 + self::IDX_COUNT] += $count; + + if ($a > 0) { + $this->samples[$this->pixelOffset * 5 + self::IDX_A] += $a * $count; + $this->samples[$this->pixelOffset * 5 + self::IDX_R] += $a * $r * $count; + $this->samples[$this->pixelOffset * 5 + self::IDX_G] += $a * $g * $count; + $this->samples[$this->pixelOffset * 5 + self::IDX_B] += $a * $b * $count; + } + } + } + + /** + * Adds a color to the buffer up until the specified x index. + * + * @param integer $color Color to write. + * @param float $untilX Samples of the color will be added the buffer until + * the cursor reaches this coordinate. + */ + public function add($color, $untilX) + { + $samplesLeft = + (int)($untilX * $this->samplesPerPixel) - + $this->subPixelOffset - + $this->pixelOffset * $this->samplesPerPixel; + + // ColorUtils methods inlined for performance reasons + $a = ($color) & 0xff; + $r = ($color >> 24) & 0xff; + $g = ($color >> 16) & 0xff; + $b = ($color >> 8) & 0xff; + + // First partial pixel + if ($this->subPixelOffset > 0) { + $samples = $this->samplesPerPixel - $this->subPixelOffset; + if ($samples > $samplesLeft) { + $samples = $samplesLeft; + } + $samplesLeft -= $samples; + + $this->_add($samples, $a, $r, $g, $b); + + $this->subPixelOffset += $samples; + if ($this->subPixelOffset == $this->samplesPerPixel) { + $this->subPixelOffset = 0; + $this->pixelOffset++; + } + } + + // Full pixels + $fullPixels = (int)($samplesLeft / $this->samplesPerPixel); + if ($fullPixels > 0) { + for ($i = 0; $i < $fullPixels; $i++) { + $this->_add($this->samplesPerPixel, $a, $r, $g, $b); + $this->pixelOffset++; + } + + $samplesLeft -= $fullPixels * $this->samplesPerPixel; + } + + // Last partial pixel + if ($samplesLeft > 0) { + $this->_add($samplesLeft, $a, $r, $g, $b); + + $this->subPixelOffset += $samplesLeft; + + if ($this->subPixelOffset == $this->samplesPerPixel) { + $this->subPixelOffset = 0; + $this->pixelOffset++; + } + } + } +} \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php new file mode 100644 index 00000000..d65b1768 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php @@ -0,0 +1,27 @@ +fromX = $fromX; + $this->toXExcl = $toXExcl; + $this->edges = array(); + } +} \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Color.php b/vendor/jdenticon/jdenticon/src/Color.php new file mode 100644 index 00000000..c07c9054 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Color.php @@ -0,0 +1,605 @@ +r = $red; + $color->g = $green; + $color->b = $blue; + $color->a = $alpha; + return $color; + } + + /** + * Creates a Color instance from HSL color parameters. + * + * @param float $hue Hue in the range [0, 1] + * @param float $saturation Saturation in the range [0, 1] + * @param float $lightness Lightness in the range [0, 1] + * @param float $alpha Alpha channel value in the range [0, 1]. + */ + public static function fromHsl($hue, $saturation, $lightness, $alpha = 1.0) + { + if ($hue < 0) $hue = 0; + if ($hue > 1) $hue = 1; + + if ($saturation < 0) $saturation = 0; + if ($saturation > 1) $saturation = 1; + + if ($lightness < 0) $lightness = 0; + if ($lightness > 1) $lightness = 1; + + if ($alpha < 0) $alpha = 0; + if ($alpha > 1) $alpha = 1; + + // Based on http://www.w3.org/TR/2011/REC-css3-color-20110607/#hsl-color + if ($saturation == 0) { + $value = (int)($lightness * 255); + return self::fromRgb($value, $value, $value, (int)($alpha * 255)); + } else { + if ($lightness <= 0.5) { + $m2 = $lightness * ($saturation + 1); + } else { + $m2 = $lightness + $saturation - $lightness * $saturation; + } + + $m1 = $lightness * 2 - $m2; + + return self::fromRgb( + self::hueToRgb($m1, $m2, $hue * 6 + 2), + self::hueToRgb($m1, $m2, $hue * 6), + self::hueToRgb($m1, $m2, $hue * 6 - 2), + (int)($alpha * 255)); + } + } + + /** + * Creates a Color> instance from HSL color parameters and will compensate + * the lightness for hues that appear to be darker than others. + * + * @param float $hue Hue in the range [0, 1]. + * @param float $saturation Saturation in the range [0, 1]. + * @param float $lightness Lightness in the range [0, 1]. + * @param float $alpha Alpha channel value in the range [0, 1]. + */ + public static function fromHslCompensated($hue, $saturation, $lightness, $alpha = 1.0) + { + if ($hue < 0) $hue = 0; + if ($hue > 1) $hue = 1; + + $lightnessCompensation = self::$lightnessCompensations[(int)($hue * 6 + 0.5)]; + + // Adjust the input lightness relative to the compensation + $lightness = $lightness < 0.5 ? + $lightness * $lightnessCompensation * 2 : + $lightnessCompensation + ($lightness - 0.5) * (1 - $lightnessCompensation) * 2; + + return self::fromHsl($hue, $saturation, $lightness, $alpha); + } + + // Helper method for FromHsl + private static function hueToRgb($m1, $m2, $h) + { + if ($h < 0) { + $h = $h + 6; + } elseif ($h > 6) { + $h = $h - 6; + } + + if ($h < 1) { + $r = $m1 + ($m2 - $m1) * $h; + } elseif ($h < 3) { + $r = $m2; + } elseif ($h < 4) { + $r = $m1 + ($m2 - $m1) * (4 - $h); + } else { + $r = $m1; + } + + return (int)(255 * $r); + } + + /** + * Gets the argb value of this color. + * + * @return int + */ + public function toRgba() + { + return + ($this->r << 24) | + ($this->g << 16) | + ($this->b << 8) | + ($this->a); + } + + /** + * Gets a hexadecimal representation of this color on the format #rrggbbaa. + * + * @return string + */ + public function __toString() + { + return '#' . bin2hex(pack('N', $this->toRgba())); + } + + /** + * Gets a hexadecimal representation of this color on the format #rrggbbaa. + * + * @return string + */ + public function toHexString($length = 8) + { + if ($length === 8) { + return $this->__toString(); + } + return '#' . substr(bin2hex(pack('N', $this->toRgba())), 0, 6); + } + + /** + * Tries to parse a value as a Color. + * + * @param mixed $value Value to parse. + * @throws InvalidArgumentException + * @return \Jdenticon\Color + */ + public static function parse($value) { + if ($value instanceof Color) { + return $value; + } + + $value = strtolower("$value"); + + if (preg_match('/^#?[0-9a-f]{3,8}$/', $value) && + self::parseHexColor($value, $result) + ) { + return $result; + } + + if (preg_match( + '/^rgba?\\(([^,]+),([^,]+),([^,]+)(?:,([^,]+))?\\)$/', + $value, $matches) && + self::parseRgbComponent($matches[1], $r) && + self::parseRgbComponent($matches[2], $g) && + self::parseRgbComponent($matches[3], $b) && + self::parseAlpha(isset($matches[4]) ? $matches[4] : null, $a) + ) { + return self::fromRgb($r, $g, $b, (int)(255 * $a)); + } + + if (preg_match( + '/^hsla?\\(([^,]+),([^,]+),([^,]+)(?:,([^,]+))?\\)$/', + $value, $matches) && + self::parseHue($matches[1], $h) && + self::parsePercent($matches[2], $s) && + self::parsePercent($matches[3], $l) && + self::parseAlpha(isset($matches[4]) ? $matches[4] : null, $a) + ) { + return self::fromHsl($h, $s, $l, $a); + } + + $result = self::parseNamedColor($value); + if ($result !== null) { + return $result; + } + + throw new \InvalidArgumentException( + "Cannot parse '$value' as a color."); + } + + /** + * Parses a percent value. + * + * @param string $input Input string. + * @param float $result Resulting value in range [0, 1]. + * + * @return boolean + */ + private static function parsePercent($input, &$result) + { + // Detect and remove percent sign + if (preg_match('/^\\s*(\\d*(?:\\.\\d*)?)%\\s*$/', $input, $matches)) { + $result = floatval($matches[1]) / 100; + + if ($result < 0) $result = 0; + if ($result > 1) $result = 1; + + return true; + } + return false; + } + + /** + * Parses an alpha value. + * + * @param string $input Input string. + * @param float $result Resulting alpha in range [0, 1]. + * + * @return boolean + */ + private static function parseAlpha($input, &$result) + { + if ($input === null || + $input === '' + ) { + $result = 1; + return true; + } + + if (preg_match('/^\\s*(\\d*(?:\\.\\d*)?)(%?)\\s*$/', $input, $matches)) { + $result = floatval($matches[1]); + + // Percentage + if ($matches[2] !== '') { + $result = $result / 100; + } + + if ($result < 0) $result = 0; + if ($result > 1) $result = 1; + + return true; + } + + return false; + } + + /** + * Parses an RGB component. + * + * @param string $input Input string. + * @param float $result Hue in range [0, 255]. + * + * @return boolean + */ + private static function parseRgbComponent($input, &$result) + { + if (preg_match('/^\\s*(\\d*(?:\\.\\d*)?)(%?)\\s*$/', $input, $matches)) { + $result = floatval($matches[1]); + + if ($matches[2] === '%') { + $result = 255 * $result / 100; + } + + $result = (int)$result; + + if ($result < 0) $result = 0; + if ($result > 255) $result = 255; + + return true; + } + return false; + } + + /** + * Parses a hue component. + * + * @param string $input Input string. + * @param float $result Hue in range [0, 1]. + * + * @return boolean + */ + private static function parseHue($input, &$result) + { + if (preg_match( + '/^\s*(\d*(?:\.\d*)?)(deg|grad|rad|turn|)\s*$/', + $input, $matches) + ) { + $result = floatval($matches[1]); + + // Percentage + switch ($matches[2]) { + case "grad": + // Gradians: range 0 - 400 + $result = $result / 400; + break; + case "rad": + // Radians: range 0 - 2pi + $result = $result / M_PI / 2; + break; + case "turn": + // Turns: range 0 - 1 + $result = $result; + break; + default: + // Degree: range 0 - 360 + $result = $result / 360; + break; + } + + $result = fmod($result, 1); + + if ($result < 0) { + $result += 1; + } + + return true; + } + return false; + } + + /** + * Parses a hex color string. + * + * @param string $input Input string. + * @param float $result Hue in range [0, 1]. + * + * @return boolean + */ + private static function parseHexColor($input, &$result) + { + if ($input[0] === '#') { + $input = substr($input, 1); + } + + // intval does not support unsigned 32-bit integers + // so we need to parse large numbers stepwise + $numeric24bit = intval(substr($input, 0, 6), 16); + $alpha8bit = intval(substr($input, 6, 2), 16); + + switch (strlen($input)) { + case 3: + $result = self::fromRgb( + (($numeric24bit & 0xf00) >> 8) | + (($numeric24bit & 0xf00) >> 4), + (($numeric24bit & 0x0f0) >> 4) | + (($numeric24bit & 0x0f0)), + (($numeric24bit & 0x00f) << 4) | + (($numeric24bit & 0x00f)) + ); + return true; + + case 4: + $result = self::fromRgb( + (($numeric24bit & 0xf000) >> 12) | + (($numeric24bit & 0xf000) >> 8), + (($numeric24bit & 0x0f00) >> 8) | + (($numeric24bit & 0x0f00) >> 4), + (($numeric24bit & 0x00f0) >> 4) | + (($numeric24bit & 0x00f0)), + (($numeric24bit & 0x000f) << 4) | + (($numeric24bit & 0x000f)) + ); + return true; + + case 6: + $result = self::fromRgb( + 0xff & ($numeric24bit >> 16), + 0xff & ($numeric24bit >> 8), + 0xff & ($numeric24bit) + ); + return true; + + case 8: + $result = self::fromRgb( + 0xff & ($numeric24bit >> 16), + 0xff & ($numeric24bit >> 8), + 0xff & ($numeric24bit), + 0xff & ($alpha8bit) + ); + return true; + } + + return false; + } + + /** + * Looks up a named color to a Color instance. + * + * @param string $input Input string. + * + * @return \Jdenticon\Color + */ + private static function parseNamedColor($input) + { + // Source: https://www.w3.org/TR/css-color-4/#named-colors + switch ($input) { + case 'aliceblue': return self::fromRgb(240,248,255); + case 'antiquewhite': return self::fromRgb(250,235,215); + case 'aqua': return self::fromRgb(0,255,255); + case 'aquamarine': return self::fromRgb(127,255,212); + case 'azure': return self::fromRgb(240,255,255); + case 'beige': return self::fromRgb(245,245,220); + case 'bisque': return self::fromRgb(255,228,196); + case 'black': return self::fromRgb(0,0,0); + case 'blanchedalmond': return self::fromRgb(255,235,205); + case 'blue': return self::fromRgb(0,0,255); + case 'blueviolet': return self::fromRgb(138,43,226); + case 'brown': return self::fromRgb(165,42,42); + case 'burlywood': return self::fromRgb(222,184,135); + case 'cadetblue': return self::fromRgb(95,158,160); + case 'chartreuse': return self::fromRgb(127,255,0); + case 'chocolate': return self::fromRgb(210,105,30); + case 'coral': return self::fromRgb(255,127,80); + case 'cornflowerblue': return self::fromRgb(100,149,237); + case 'cornsilk': return self::fromRgb(255,248,220); + case 'crimson': return self::fromRgb(220,20,60); + case 'cyan': return self::fromRgb(0,255,255); + case 'darkblue': return self::fromRgb(0,0,139); + case 'darkcyan': return self::fromRgb(0,139,139); + case 'darkgoldenrod': return self::fromRgb(184,134,11); + case 'darkgray': return self::fromRgb(169,169,169); + case 'darkgreen': return self::fromRgb(0,100,0); + case 'darkgrey': return self::fromRgb(169,169,169); + case 'darkkhaki': return self::fromRgb(189,183,107); + case 'darkmagenta': return self::fromRgb(139,0,139); + case 'darkolivegreen': return self::fromRgb(85,107,47); + case 'darkorange': return self::fromRgb(255,140,0); + case 'darkorchid': return self::fromRgb(153,50,204); + case 'darkred': return self::fromRgb(139,0,0); + case 'darksalmon': return self::fromRgb(233,150,122); + case 'darkseagreen': return self::fromRgb(143,188,143); + case 'darkslateblue': return self::fromRgb(72,61,139); + case 'darkslategray': return self::fromRgb(47,79,79); + case 'darkslategrey': return self::fromRgb(47,79,79); + case 'darkturquoise': return self::fromRgb(0,206,209); + case 'darkviolet': return self::fromRgb(148,0,211); + case 'deeppink': return self::fromRgb(255,20,147); + case 'deepskyblue': return self::fromRgb(0,191,255); + case 'dimgray': return self::fromRgb(105,105,105); + case 'dimgrey': return self::fromRgb(105,105,105); + case 'dodgerblue': return self::fromRgb(30,144,255); + case 'firebrick': return self::fromRgb(178,34,34); + case 'floralwhite': return self::fromRgb(255,250,240); + case 'forestgreen': return self::fromRgb(34,139,34); + case 'fuchsia': return self::fromRgb(255,0,255); + case 'gainsboro': return self::fromRgb(220,220,220); + case 'ghostwhite': return self::fromRgb(248,248,255); + case 'gold': return self::fromRgb(255,215,0); + case 'goldenrod': return self::fromRgb(218,165,32); + case 'gray': return self::fromRgb(128,128,128); + case 'green': return self::fromRgb(0,128,0); + case 'greenyellow': return self::fromRgb(173,255,47); + case 'grey': return self::fromRgb(128,128,128); + case 'honeydew': return self::fromRgb(240,255,240); + case 'hotpink': return self::fromRgb(255,105,180); + case 'indianred': return self::fromRgb(205,92,92); + case 'indigo': return self::fromRgb(75,0,130); + case 'ivory': return self::fromRgb(255,255,240); + case 'khaki': return self::fromRgb(240,230,140); + case 'lavender': return self::fromRgb(230,230,250); + case 'lavenderblush': return self::fromRgb(255,240,245); + case 'lawngreen': return self::fromRgb(124,252,0); + case 'lemonchiffon': return self::fromRgb(255,250,205); + case 'lightblue': return self::fromRgb(173,216,230); + case 'lightcoral': return self::fromRgb(240,128,128); + case 'lightcyan': return self::fromRgb(224,255,255); + case 'lightgoldenrodyellow': return self::fromRgb(250,250,210); + case 'lightgray': return self::fromRgb(211,211,211); + case 'lightgreen': return self::fromRgb(144,238,144); + case 'lightgrey': return self::fromRgb(211,211,211); + case 'lightpink': return self::fromRgb(255,182,193); + case 'lightsalmon': return self::fromRgb(255,160,122); + case 'lightseagreen': return self::fromRgb(32,178,170); + case 'lightskyblue': return self::fromRgb(135,206,250); + case 'lightslategray': return self::fromRgb(119,136,153); + case 'lightslategrey': return self::fromRgb(119,136,153); + case 'lightsteelblue': return self::fromRgb(176,196,222); + case 'lightyellow': return self::fromRgb(255,255,224); + case 'lime': return self::fromRgb(0,255,0); + case 'limegreen': return self::fromRgb(50,205,50); + case 'linen': return self::fromRgb(250,240,230); + case 'magenta': return self::fromRgb(255,0,255); + case 'maroon': return self::fromRgb(128,0,0); + case 'mediumaquamarine': return self::fromRgb(102,205,170); + case 'mediumblue': return self::fromRgb(0,0,205); + case 'mediumorchid': return self::fromRgb(186,85,211); + case 'mediumpurple': return self::fromRgb(147,112,219); + case 'mediumseagreen': return self::fromRgb(60,179,113); + case 'mediumslateblue': return self::fromRgb(123,104,238); + case 'mediumspringgreen': return self::fromRgb(0,250,154); + case 'mediumturquoise': return self::fromRgb(72,209,204); + case 'mediumvioletred': return self::fromRgb(199,21,133); + case 'midnightblue': return self::fromRgb(25,25,112); + case 'mintcream': return self::fromRgb(245,255,250); + case 'mistyrose': return self::fromRgb(255,228,225); + case 'moccasin': return self::fromRgb(255,228,181); + case 'navajowhite': return self::fromRgb(255,222,173); + case 'navy': return self::fromRgb(0,0,128); + case 'oldlace': return self::fromRgb(253,245,230); + case 'olive': return self::fromRgb(128,128,0); + case 'olivedrab': return self::fromRgb(107,142,35); + case 'orange': return self::fromRgb(255,165,0); + case 'orangered': return self::fromRgb(255,69,0); + case 'orchid': return self::fromRgb(218,112,214); + case 'palegoldenrod': return self::fromRgb(238,232,170); + case 'palegreen': return self::fromRgb(152,251,152); + case 'paleturquoise': return self::fromRgb(175,238,238); + case 'palevioletred': return self::fromRgb(219,112,147); + case 'papayawhip': return self::fromRgb(255,239,213); + case 'peachpuff': return self::fromRgb(255,218,185); + case 'peru': return self::fromRgb(205,133,63); + case 'pink': return self::fromRgb(255,192,203); + case 'plum': return self::fromRgb(221,160,221); + case 'powderblue': return self::fromRgb(176,224,230); + case 'purple': return self::fromRgb(128,0,128); + case 'rebeccapurple': return self::fromRgb(102,51,153); + case 'red': return self::fromRgb(255,0,0); + case 'rosybrown': return self::fromRgb(188,143,143); + case 'royalblue': return self::fromRgb(65,105,225); + case 'saddlebrown': return self::fromRgb(139,69,19); + case 'salmon': return self::fromRgb(250,128,114); + case 'sandybrown': return self::fromRgb(244,164,96); + case 'seagreen': return self::fromRgb(46,139,87); + case 'seashell': return self::fromRgb(255,245,238); + case 'sienna': return self::fromRgb(160,82,45); + case 'silver': return self::fromRgb(192,192,192); + case 'skyblue': return self::fromRgb(135,206,235); + case 'slateblue': return self::fromRgb(106,90,205); + case 'slategray': return self::fromRgb(112,128,144); + case 'slategrey': return self::fromRgb(112,128,144); + case 'snow': return self::fromRgb(255,250,250); + case 'springgreen': return self::fromRgb(0,255,127); + case 'steelblue': return self::fromRgb(70,130,180); + case 'tan': return self::fromRgb(210,180,140); + case 'teal': return self::fromRgb(0,128,128); + case 'thistle': return self::fromRgb(216,191,216); + case 'tomato': return self::fromRgb(255,99,71); + case 'transparent': return self::fromRgb(0,0,0,0); + case 'turquoise': return self::fromRgb(64,224,208); + case 'violet': return self::fromRgb(238,130,238); + case 'wheat': return self::fromRgb(245,222,179); + case 'white': return self::fromRgb(255,255,255); + case 'whitesmoke': return self::fromRgb(245,245,245); + case 'yellow': return self::fromRgb(255,255,0); + case 'yellowgreen': return self::fromRgb(154,205,50); + default: return null; + } + } +} diff --git a/vendor/jdenticon/jdenticon/src/Identicon.php b/vendor/jdenticon/jdenticon/src/Identicon.php new file mode 100644 index 00000000..48183b86 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Identicon.php @@ -0,0 +1,492 @@ +iconGenerator = IconGenerator::getDefaultGenerator(); + + if ($options !== null) { + $this->setOptions($options); + } + + if ($this->style === null) { + $this->style = new IdenticonStyle(); + } + } + + /** + * Creates an Identicon instance from a specified hash. + * + * @param string $hash A binary string containing the hash that will be used + * as base for this icon. The hash must contain at least 6 bytes. + * @param int $size The size of the icon in pixels (the icon is quadratic). + * @return \Jdenticon\Identicon + */ + public static function fromHash($hash, $size) + { + return new Identicon(array('hash' => $hash, 'size' => $size)); + } + + /** + * Creates an Identicon instance from a specified value. + * + * @param mixed $value The value that will be used as base for this icon. + * The value will be converted to a UTF8 encoded string and then hashed + * using SHA1. + * @param int $size The size of the icon in pixels (the icon is quadratic). + * @return \Jdenticon\Identicon + */ + public static function fromValue($value, $size) + { + return new Identicon(array('value' => $value, 'size' => $size)); + } + + /** + * Gets an associative array of all options of this identicon. + * + * @return array + */ + public function getOptions() + { + $options = array(); + + if ($this->valueSet) { + $options['value'] = $this->getValue(); + } elseif ($this->hash !== null) { + $options['hash'] = $this->getHash(); + } + + $options['size'] = $this->getSize(); + $options['style'] = $this->getStyle()->getOptions(); + + if ($this->enableImageMagick !== null) { + $options['enableImageMagick'] = $this->getEnableImageMagick(); + } + + if ($this->iconGenerator !== IconGenerator::getDefaultGenerator()) { + $options['iconGenerator'] = $this->getIconGenerator(); + } + + return $options; + } + + /** + * Sets options in this identicon by specifying an associative array of + * option values. + * + * @param array $options Options to set. + * @return self + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $this->__set($key, $value); + } + return $this; + } + + public function __get($name) + { + switch (strtolower($name)) { + case 'size': + return $this->getSize(); + case 'hash': + return $this->getHash(); + case 'value': + return $this->getValue(); + case 'style': + return $this->getStyle(); + case 'icongenerator': + return $this->getIconGenerator(); + case 'enableimagemagick': + return $this->getEnableImageMagick(); + default: + throw new \InvalidArgumentException( + "Unknown Identicon option '$name'."); + } + } + + public function __set($name, $value) + { + switch (strtolower($name)) { + case 'size': + $this->setSize($value); + break; + case 'hash': + $this->setHash($value); + break; + case 'value': + $this->setValue($value); + break; + case 'style': + $this->setStyle($value); + break; + case 'icongenerator': + $this->setIconGenerator($value); + break; + case 'enableimagemagick': + $this->setEnableImageMagick($value); + break; + default: + throw new \InvalidArgumentException( + "Unknown Identicon option '$name'."); + } + } + + /** + * Gets the size of the icon in pixels. + */ + public function getSize() + { + return $this->size; + } + + /** + * Sets the size of this icon in pixels. + * + * @param int|float|double $size The width and height of the icon. + */ + public function setSize($size) + { + if (!is_numeric($size) || $size < 1) { + throw new \InvalidArgumentException( + "An invalid identicon size was specified. ". + "A numeric value >= 1 was expected. Specified value: $size."); + } + + $this->size = (int)$size; + } + + /** + * Gets the size of the icon in pixels. + */ + public function getEnableImageMagick() + { + // Enable ImageMagick on PHP < 7. On PHP 7 the performance increase + // is not as obvious as on PHP 5. Since the ImageMagick renderer has a + // lot of quirks, we don't want to use it unless really needed. + if ($this->enableImageMagick === null) { + return PHP_MAJOR_VERSION < 7 && extension_loaded('imagick'); + } + + return $this->enableImageMagick; + } + + /** + * Sets whether ImageMagick should be used to generate PNG icons. + * + * @param bool $enable true to enable ImageMagick. + */ + public function setEnableImageMagick($enable) + { + if (!is_bool($enable)) { + throw new \InvalidArgumentException( + "enableImageMagick can only assume boolean values. Specified value: $enable."); + } + + // Verify that the Imagick extension is installed + if ($enable && !extension_loaded('imagick')) { + throw new \Exception( + 'Failed to enable ImageMagick. '. + 'The Imagick PHP extension was not found on this system.'); + } + + $this->enableImageMagick = $enable; + } + + /** + * Gets the {@see IconGenerator} used to generate icons. + * + * @return \Jdenticon\Rendering\IconGenerator + */ + public function getIconGenerator() + { + return $this->iconGenerator; + } + + /** + * Sets the {@see IconGenerator} used to generate icons. + * + * @param \Jdenticon\Rendering\IconGenerator $iconGenerator Icon generator + * that will render the shapes of the identicon. + * @return \Jdenticon\Identicon + */ + public function setIconGenerator(IconGenerator $iconGenerator) + { + if ($iconGenerator === null) { + $iconGenerator = IconGenerator::getDefaultGenerator(); + } + $this->iconGenerator = $iconGenerator; + return $this; + } + + /** + * Gets or sets the style of the icon. + * + * @return \Jdenticon\IdenticonStyle + */ + public function getStyle() + { + return $this->style; + } + + /** + * Gets or sets the style of the icon. + * + * @param array|\Jdenticon\IdenticonStyle $style The new style of the icon. + * NULL will revert the identicon to use the default style. + * @return self + */ + public function setStyle($style) + { + if ($style == null) { + $this->style = new IdenticonStyle(); + } elseif ($style instanceof IdenticonStyle) { + $this->style = $style; + } elseif (is_array($style)) { + $this->style = new IdenticonStyle($style); + } else { + throw new \InvalidArgumentException( + "Invalid indenticon style was specified. ". + "Allowed values are IdenticonStyle instances and associative ". + "arrays containing IdenticonStyle options."); + } + + return $this; + } + + /** + * Gets a binary string containing the hash that is used as base for this + * icon. + */ + public function getHash() + { + return $this->hash; + } + + /** + * Sets a binary string containing the hash that is used as base for this + * icon. The string should contain at least 6 bytes. + * + * @param string $hash Binary string containing the hash. + */ + public function setHash($hash) + { + if (!is_string($hash)) { + throw new \InvalidArgumentException( + 'An invalid $hash was passed to Identicon. ' . + 'A binary string was expected.'); + } + if (strlen($hash) < 6) { + throw new \InvalidArgumentException( + 'An invalid $hash was passed to Identicon. ' . + 'The hash was expected to contain at least 6 bytes.'); + } + + $this->hash = $hash; + $this->value = null; + $this->valueSet = false; + return $this; + } + + /** + * Gets a binary string containing the hash that is used as base for this + * icon. + */ + public function getValue() + { + return $this->value; + } + + /** + * Sets a value that will be used as base for this icon. The value will + * be converted to a string and then hashed using SHA1. + * + * @param mixed $value Value that will be hashed. + */ + public function setValue($value) + { + $this->hash = sha1("$value"); + $this->value = $value; + $this->valueSet = true; + return $this; + } + + /** + * Gets the bounds of the icon excluding its padding. + * + * @return \Jdenticon\Rendering\Rectangle + */ + public function getIconBounds() + { + // Round padding to nearest integer + $padding = (int)($this->style->getPadding() * $this->size + 0.5); + + return new Rectangle( + $padding, $padding, + $this->size - $padding * 2, + $this->size - $padding * 2); + } + + private function getRenderer($imageFormat) + { + switch (strtolower($imageFormat)) { + case 'svg': + return new SvgRenderer($this->size, $this->size); + + default: + return $this->getEnableImageMagick() ? + new ImagickRenderer($this->size, $this->size) : + new InternalPngRenderer($this->size, $this->size); + } + } + + /** + * Draws this icon using a specified renderer. + * + * This method is only intended for usage with custom renderers. A custom + * renderer could as an example render an Identicon in a file format not + * natively supported by Jdenticon. To implement a new file format, + * implement {@see \Jdenticon\Rendering\RendererInterface}. + * + * @param \Jdenticon\Rendering\RendererInterface $renderer The renderer used + * to render this icon. + * @param \Jdenticon\Rendering\Rectangle $rect The bounds of the rendered + * icon. No padding will be applied to the rectangle. If the parameter + * is omitted, the rectangle is calculated from the current icon + * size and padding. + */ + public function draw( + \Jdenticon\Rendering\RendererInterface $renderer, + \Jdenticon\Rendering\Rectangle $rect = null) + { + if ($rect === null) { + $rect = $this->getIconBounds(); + } + $this->iconGenerator->generate( + $renderer, $rect, $this->style, $this->hash); + } + + /** + * Renders the icon directly to the page output. + * + * The method will set the 'Content-Type' HTTP header. You are recommended + * to set an appropriate 'Cache-Control' header before calling this method + * to ensure the icon is cached client side. + * + * @param string $imageFormat The image format of the output. + * Supported values are 'png' and 'svg'. + */ + public function displayImage($imageFormat = 'png') + { + $renderer = $this->getRenderer($imageFormat); + $this->draw($renderer, $this->getIconBounds()); + $mimeType = $renderer->getMimeType(); + $data = $renderer->getData(); + header("Content-Type: $mimeType"); + echo $data; + } + + /** + * Renders the icon to a binary string. + * + * @param string $imageFormat The image format of the output string. + * Supported values are 'png' and 'svg'. + * @return string + */ + public function getImageData($imageFormat = 'png') + { + $renderer = $this->getRenderer($imageFormat); + $this->draw($renderer, $this->getIconBounds()); + return $renderer->getData(); + } + + /** + * Renders the icon as a data URI. It is recommended to avoid using this + * method unless really necessary, since it will effectively disable client + * caching of generated icons, and will also cause the same icon to be + * rendered multiple times, when used multiple times on a single page. + * + * @param string $imageFormat The image format of the data URI. + * Supported values are 'png' and 'svg'. + * @return string + */ + public function getImageDataUri($imageFormat = 'png') + { + $renderer = $this->getRenderer($imageFormat); + $this->draw($renderer, $this->getIconBounds()); + $mimeType = $renderer->getMimeType(); + $base64 = base64_encode($renderer->getData()); + return "data:$mimeType;base64,$base64"; + } +} + + diff --git a/vendor/jdenticon/jdenticon/src/IdenticonStyle.php b/vendor/jdenticon/jdenticon/src/IdenticonStyle.php new file mode 100644 index 00000000..ad388c5e --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/IdenticonStyle.php @@ -0,0 +1,460 @@ +backgroundColor = self::getDefaultBackgroundColor(); + $this->padding = self::getDefaultPadding(); + $this->colorSaturation = self::getDefaultColorSaturation(); + $this->grayscaleSaturation = self::getDefaultGrayscaleSaturation(); + $this->colorLightness = self::getDefaultColorLightness(); + $this->grayscaleLightness = self::getDefaultGrayscaleLightness(); + + if ($options !== null) { + $this->setOptions($options); + } + } + + /** + * Gets an associative array of all options of this style. + * + * @return array + */ + public function getOptions() + { + $options = array(); + + $options['backgroundColor'] = $this->getBackgroundColor()->__toString(); + $options['padding'] = $this->getPadding(); + $options['colorSaturation'] = $this->getColorSaturation(); + $options['grayscaleSaturation'] = $this->getGrayscaleSaturation(); + $options['colorLightness'] = $this->getColorLightness(); + $options['grayscaleLightness'] = $this->getGrayscaleLightness(); + + if ($this->hues !== null) { + $options['hues'] = $this->getHues(); + } + + return $options; + } + + /** + * Sets options in this style by specifying an associative array of option + * values. + * + * @param array $options Options to set. + * @return self + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $this->__set($key, $value); + } + return $this; + } + + public function __get($name) + { + switch (strtolower($name)) { + case 'backgroundcolor': + return $this->getBackgroundColor(); + case 'padding': + return $this->getPadding(); + case 'colorsaturation': + return $this->getColorSaturation(); + case 'grayscalesaturation': + return $this->getGrayscaleSaturation(); + case 'colorlightness': + return $this->getColorLightness(); + case 'grayscalelightness': + return $this->getGrayscaleLightness(); + case 'hues': + return $this->getHues(); + default: + throw new \InvalidArgumentException( + "Unknown IdenticonStyle option '$name'."); + } + } + + public function __set($name, $value) + { + switch (strtolower($name)) { + case 'backgroundcolor': + $this->setBackgroundColor($value); + break; + case 'padding': + $this->setPadding($value); + break; + case 'colorsaturation': + $this->setColorSaturation($value); + break; + case 'grayscalesaturation': + $this->setGrayscaleSaturation($value); + break; + case 'colorlightness': + $this->setColorLightness($value); + break; + case 'grayscalelightness': + $this->setGrayscaleLightness($value); + break; + case 'hues': + $this->setHues($value); + break; + default: + throw new \InvalidArgumentException( + "Unknown IdenticonStyle option '$name'."); + } + } + + /** + * Normalizes a hue to the first turn [0, 360). + * + * @param mixed $hue + * @return integer + */ + private static function normalizeHue($hue) + { + if (!is_numeric($hue)) { + throw new \InvalidArgumentException( + "'$hue' is not a valid hue."); + } + + $hue = $hue % 360; + if ($hue < 0) { + $hue += 360; + } + + return $hue; + } + + /** + * Gets an array of allowed hues, or null if there are no restrictions. + * + * @return array(int)|null + */ + public function getHues() + { + return $this->hues; + } + + /** + * Sets the allowed hues of generated icons. + * + * @param array(integer)|integer|null $value A hue specified in degrees, + * or an array of hues specified in degrees. If set to null, the hue + * list is cleared. + * @return self + */ + public function setHues($value) + { + $hues = array(); + + if ($value !== null) { + if (is_array($value)) { + foreach ($value as $hue) { + $hues[] = self::normalizeHue($hue); + } + } else { + $hues[] = self::normalizeHue($value); + } + } + + $this->hues = empty($hues) ? null : $hues; + return $this; + } + + /** + * Gets the padding of an icon in percents in the range [0.0, 0.4]. + * + * @return float + */ + public function getPadding() + { + return $this->padding; + } + + /** + * Sets the padding of an icon in percents. + * + * @param float $value New padding in the range [0.0, 0.4]. + * @return self + */ + public function setPadding($value) + { + if (!is_numeric($value) || $value < 0 || $value > 0.4) { + throw new \InvalidArgumentException( + "Padding '$value' out of range. ". + "Values in the range [0.0, 0.4] are allowed."); + } + $this->padding = (float)$value; + return $this; + } + + /** + * Gets the color of the identicon background. + * + * @return \Jdenticon\Color + */ + public function getBackgroundColor() + { + return $this->backgroundColor; + } + + /** + * Sets the color of the identicon background. + * + * @param \Jdenticon\Color|string $value New background color. + * @return \Jdenticon\IdenticonStyle + */ + public function setBackgroundColor($value) + { + if ($value instanceof Color) { + $this->backgroundColor = $value; + } else { + $this->backgroundColor = Color::parse($value); + } + + return $this; + } + + /** + * Gets the saturation of the originally grayscale identicon shapes. + * + * @return float Saturation in the range [0.0, 1.0]. + */ + public function getGrayscaleSaturation() + { + return $this->grayscaleSaturation; + } + + /** + * Sets the saturation of the originally grayscale identicon shapes. + * + * @param $value float Saturation in the range [0.0, 1.0]. + * @return self + */ + public function setGrayscaleSaturation($value) + { + if (!is_numeric($value) || + $value < 0 || $value > 1 + ) { + throw new \InvalidArgumentException( + "The grayscale saturation was invalid. ". + "Only values in the range [0.0, 1.0] are allowed."); + } + $this->grayscaleSaturation = (float)$value; + return $this; + } + + /** + * Gets the saturation of the colored identicon shapes. + * + * @return float Saturation in the range [0.0, 1.0]. + */ + public function getColorSaturation() + { + return $this->colorSaturation; + } + + /** + * Sets the saturation of the colored identicon shapes. + * + * @param $value float Saturation in the range [0.0, 1.0]. + * @return self + */ + public function setColorSaturation($value) + { + if (!is_numeric($value) || + $value < 0 || $value > 1 + ) { + throw new \InvalidArgumentException( + "The color saturation was invalid. ". + "Only values in the range [0.0, 1.0] are allowed."); + } + $this->colorSaturation = (float)$value; + return $this; + } + + /** + * Gets the value of the ColorLightness property. + * + * @return array(float, float) + */ + public function getColorLightness() + { + return $this->colorLightness; + } + + /** + * Sets the value of the ColorLightness property. + * + * @param $value array(float, float) Lightness range. + * @return self + */ + public function setColorLightness($value) + { + if (!is_array($value) || + !array_key_exists(0, $value) || + !array_key_exists(1, $value) || + !is_numeric($value[0]) || + !is_numeric($value[1]) || + $value[0] < 0 || $value[0] > 1 || + $value[1] < 0 || $value[1] > 1 + ) { + throw new \InvalidArgumentException( + "The value passed to setColorLightness was invalid. ". + "Please check the documentation."); + } + + $this->colorLightness = array((float)$value[0], (float)$value[1]); + return $this; + } + + /** + * Gets the value of the GrayscaleLightness property. + * + * @return array(float, float) + */ + public function getGrayscaleLightness() + { + return $this->grayscaleLightness; + } + + /** + * Sets the value of the GrayscaleLightness property. + * + * @param $value array(float, float) Lightness range. + * @return self + */ + public function setGrayscaleLightness($value) + { + if (!is_array($value) || + !array_key_exists(0, $value) || + !array_key_exists(1, $value) || + !is_numeric($value[0]) || + !is_numeric($value[1]) || + $value[0] < 0 || $value[0] > 1 || + $value[1] < 0 || $value[1] > 1 + ) { + throw new \InvalidArgumentException( + "The value passed to setGrayscaleLightness was invalid. ". + "Please check the documentation."); + } + $this->grayscaleLightness = array((float)$value[0], (float)$value[1]); + return $this; + } + + + + /** + * Gets the default value of the BackgroundColor property. Resolves to transparent. + * + * @return \Jdenticon\Color + */ + public static function getDefaultBackgroundColor() + { + return Color::fromRgb(255, 255, 255, 255); + } + + /** + * Gets the default value of the Padding property. Resolves to 0.08. + * + * @return float + */ + public static function getDefaultPadding() + { + return 0.08; + } + + /** + * Gets the default value of the ColorSaturation property. Resolves to 0.5. + * + * @return float + */ + public static function getDefaultColorSaturation() + { + return 0.5; + } + + /** + * Gets the default value of the GrayscaleSaturation property. Resolves to 0. + * + * @return float + */ + public static function getDefaultGrayscaleSaturation() + { + return 0; + } + + /** + * Gets the default value of the ColorLightness property. Resolves to [0.4, 0.8]. + * + * @return array + */ + public static function getDefaultColorLightness() + { + return array(0.4, 0.8); + } + + /** + * Gets the default value of the GrayscaleLightness property. Resolves to [0.3, 0.9]. + * + * @return array + */ + public static function getDefaultGrayscaleLightness() + { + return array(0.3, 0.9); + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php b/vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php new file mode 100644 index 00000000..0aeac805 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php @@ -0,0 +1,209 @@ +transform = Transform::getEmpty(); + } + + /** + * Sets the current transform that will be applied on all coordinates before + * being rendered to the target image. + * + * @param \Jdenticon\Rendering\Transform $transform The transform to set. + * If NULL is specified any existing transform is removed. + */ + public function setTransform(\Jdenticon\Rendering\Transform $transform) + { + $this->transform = $transform === null ? + Transform::getEmpty() : $transform; + } + + /** + * Gets the current transform that will be applied on all coordinates before + * being rendered to the target image. + * + * @return \Jdenticon\Rendering\Transform + */ + public function getTransform() + { + return $this->transform; + } + + /** + * Adds a polygon without translating its coordinates. + * + * @param array $points An array of the points that the polygon consists of. + */ + abstract protected function addPolygonNoTransform($points); + + /** + * Adds a circle without translating its coordinates. + * + * @param float $x The x-coordinate of the bounding rectangle + * upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle + * upper-left corner. + * @param float $size The size of the bounding rectangle. + * @param bool $counterClockwise If true the circle will be drawn + * counter clockwise. + */ + abstract protected function addCircleNoTransform($x, $y, $size, $counterClockwise); + + /** + * Sets the background color of the image. + * + * @param \Jdenticon\Color $color The image background color. + */ + public function setBackgroundColor(\Jdenticon\Color $color) + { + $this->backgroundColor = $color; + } + + /** + * Gets the background color of the image. + * + * @return \Jdenticon\Color + */ + public function getBackgroundColor() + { + return $this->backgroundColor; + } + + private function addPolygonCore(array $points, $invert) + { + $transformedPoints = array(); + foreach ($points as $point) { + $transformedPoints[] = + $this->transform->transformPoint($point->x, $point->y); + } + + if ($invert) { + $transformedPoints = array_reverse($transformedPoints); + } + + //var_dump($transformedPoints); + + $this->addPolygonNoTransform($transformedPoints); + } + + /** + * Adds a rectangle to the image. + * + * @param float $x The x-coordinate of the rectangle upper-left corner. + * @param float $y The y-coordinate of the rectangle upper-left corner. + * @param float $width The width of the rectangle. + * @param float $height The height of the rectangle. + * @param bool $invert If true the area of the rectangle will be removed + * from the filled area. + */ + public function addRectangle($x, $y, $width, $height, $invert = false) + { + $this->addPolygonCore(array( + new Point($x, $y), + new Point($x + $width, $y), + new Point($x + $width, $y + $height), + new Point($x, $y + $height), + ), $invert); + } + + /** + * Adds a circle to the image. + * + * @param float $x The x-coordinate of the bounding rectangle + * upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle + * upper-left corner. + * @param float $size The size of the bounding rectangle. + * @param bool $invert If true the area of the circle will be removed + * from the filled area. + */ + public function addCircle($x, $y, $size, $invert = false) + { + $northWest = $this->transform->transformPoint($x, $y, $size, $size); + $this->addCircleNoTransform($northWest->x, $northWest->y, $size, $invert); + } + + /** + * Adds a polygon to the image. + * + * @param array $points Array of points that the polygon consists of. + * @param bool $invert If true the area of the polygon will be removed + * from the filled area. + */ + public function addPolygon($points, $invert = false) + { + $this->addPolygonCore($points, $invert); + } + + /** + * Adds a triangle to the image. + * + * @param float $x The x-coordinate of the bounding rectangle + * upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle + * upper-left corner. + * @param float $width The width of the bounding rectangle. + * @param float $height The height of the bounding rectangle. + * @param float $direction The direction of the 90 degree corner of the + * triangle. + * @param bool $invert If true the area of the triangle will be removed + * from the filled area. + */ + public function addTriangle($x, $y, $width, $height, $direction, $invert = false) + { + $points = array( + new Point($x + $width, $y), + new Point($x + $width, $y + $height), + new Point($x, $y + $height), + new Point($x, $y) + ); + + array_splice($points, $direction, 1); + + $this->addPolygonCore($points, $invert); + } + + /** + * Adds a rhombus to the image. + * + * @param float $x The x-coordinate of the bounding rectangle + * upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle + * upper-left corner. + * @param float $width The width of the bounding rectangle. + * @param float $height The height of the bounding rectangle. + * @param bool $invert If true the area of the rhombus will be removed + * from the filled area. + */ + public function addRhombus($x, $y, $width, $height, $invert = false) + { + $this->addPolygonCore(array( + new Point($x + $width / 2, $y), + new Point($x + $width, $y + $height / 2), + new Point($x + $width / 2, $y + $height), + new Point($x, $y + $height / 2), + ), $invert); + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php b/vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php new file mode 100644 index 00000000..24af0f97 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php @@ -0,0 +1,84 @@ +getGrayscaleLightness(); + $colorLightness = $style->getColorLightness(); + $hues = $style->getHues(); + + if ($hues !== null) { + // $hue is in the range [0, 1] + // Multiply with 0.999 to change the range to [0, 1) + $hueIndex = (int)($hue * 0.999 * count($hues)); + $hue = (float)$hues[$hueIndex] / 360; + } + + $this->darkGray = Color::fromHslCompensated( + $hue, $style->getGrayscaleSaturation(), $grayscaleLightness[0]); + $this->midColor = Color::fromHslCompensated( + $hue, $style->getColorSaturation(), ($colorLightness[0] + $colorLightness[1]) / 2); + $this->lightGray = Color::fromHslCompensated( + $hue, $style->getGrayscaleSaturation(), $grayscaleLightness[1]); + $this->lightColor = Color::fromHslCompensated( + $hue, $style->getColorSaturation(), $colorLightness[1]); + $this->darkColor = Color::fromHslCompensated( + $hue, $style->getColorSaturation(), $colorLightness[0]); + } + + /** + * Gets a color from this color theme by index. + * + * @param int $index Color index in the range [0, getCount()). + * @return Jdenticon\Color + */ + public function getByIndex($index) + { + if ($index === 0) return $this->darkGray; + if ($index === 1) return $this->midColor; + if ($index === 2) return $this->lightGray; + if ($index === 3) return $this->lightColor; + if ($index === 4) return $this->darkColor; + return null; + } + + /** + * Gets the number of available colors in this theme. + * + * @return int + */ + public function getCount() + { + return 5; + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php b/vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php new file mode 100644 index 00000000..d31fdf3b --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php @@ -0,0 +1,290 @@ +defaultShapes = array( + // Sides + new ShapeCategory( + /*$colorIndex=*/ 8, + /*$shapes=*/ ShapeDefinitions::getOuterShapes(), + /*$shapeIndex=*/ 2, + /*$rotationIndex=*/ 3, + /*$positions=*/ array(1,0, 2,0, 2,3, 1,3, 0,1, 3,1, 3,2, 0,2) + ), + + // Corners + new ShapeCategory( + /*$colorIndex=*/ 9, + /*$shapes=*/ ShapeDefinitions::getOuterShapes(), + /*$shapeIndex=*/ 4, + /*$rotationIndex=*/ 5, + /*$positions=*/ array(0,0, 3,0, 3,3, 0,3) + ), + + // Center + new ShapeCategory( + /*$colorIndex=*/ 10, + /*$shapes=*/ ShapeDefinitions::getCenterShapes(), + /*$shapeIndex=*/ 1, + /*$rotationIndex=*/ null, + /*$positions=*/ array(1,1, 2,1, 2,2, 1,2) + ) + ); + } + + public static function getDefaultGenerator() + { + if (self::$instance === null) { + self::$instance = new IconGenerator(); + } + return self::$instance; + } + + /** + * Gets the number of cells in each direction of the icons generated by + * this IconGenerator. + * + * @return int + */ + public function getCellCount() + { + return 4; + } + + /** + * Determines the hue to be used in an icon for the specified hash. + * + * @return float Hue in the range [0, 1]. + */ + protected static function getHue($hash) + { + $value = hexdec(substr($hash, -7)); + return $value / 0xfffffff; + } + + /** + * Determines whether $newValue is duplicated in $source if all values + * in $duplicateValues are determined to be equal. + * + * @return bool + */ + private static function isDuplicate( + array $source, $newValue, + array $duplicateValues) + { + if (in_array($newValue, $duplicateValues, true)) { + foreach ($duplicateValues as $value) { + if (in_array($value, $source, true)) { + return true; + } + } + } + return false; + } + + /** + * Gets the specified octet from a byte array. + * + * @param string $hash The hexstring from which the octet will be retrieved. + * @param int $index The zero-based index of the octet to be returned. + * @return int + */ + protected static function getOctet($hash, $index) + { + return hexdec($hash[$index]); + } + + /** + * Gets an array of the shape categories to be rendered in icons generated + * by this IconGenerator. + * + * @return array + */ + protected function getCategories() + { + return $this->defaultShapes; + } + + /** + * Gets an enumeration of individual shapes to be rendered in an icon for a + * specific hash. + * + * @param \Jdenticon\Rendering\ColorTheme $colorTheme A color theme + * specifying the colors to be used in the icon. + * @param string $hash The hash for which the shapes will be returned. + * @return array(Jdenticon\Shapes\Shape) + */ + protected function getShapes($colorTheme, $hash) + { + $usedColorThemeIndexes = array(); + $categories = self::getCategories(); + $shapes = array(); + $colorCount = $colorTheme->getCount(); + + foreach ($categories as $category) { + $colorThemeIndex = + self::getOctet($hash, $category->colorIndex) % $colorCount; + + if (self::isDuplicate( + // Disallow dark gray and dark color combo + $usedColorThemeIndexes, $colorThemeIndex, array(0, 4)) || + self::isDuplicate( + // Disallow light gray and light color combo + $usedColorThemeIndexes, $colorThemeIndex, array(2, 3)) + ) { + $colorThemeIndex = 1; + } + + $usedColorThemeIndexes[] = $colorThemeIndex; + + $startRotationIndex = $category->rotationIndex === null ? + 0 : self::getOctet($hash, $category->rotationIndex); + $shapeIndex = + self::getOctet($hash, $category->shapeIndex) % + count($category->shapes); + $shape = $category->shapes[$shapeIndex]; + + $shapes[] = new Shape( + /*$definition=*/ $shape, + /*$color=*/ $colorTheme->getByIndex($colorThemeIndex), + /*$positions=*/ $category->positions, + /*$startRotationIndex=*/ $startRotationIndex + ); + } + + return $shapes; + } + + /** + * Creates a quadratic copy of the specified + * {@link \Jdenticon\Rendering\Rectangle} with a multiple of the cell count + * as size. + * + * @param \Jdenticon\Rendering\Rectangle $rect The rectangle to be + * normalized. + */ + protected function normalizeRectangle(\Jdenticon\Rendering\Rectangle $rect) + { + $size = (int)min($rect->width, $rect->height); + + // Make size a multiple of the cell count + $size -= $size % $this->getCellCount(); + + return new Rectangle( + (int)($rect->x + ($rect->width - $size) / 2), + (int)($rect->y + ($rect->height - $size) / 2), + $size, + $size); + } + + /** + * Renders the background of an icon. + * + * @param \Jdenticon\Rendering\RendererInterface $renderer The renderer to + * be used for rendering the icon on the target surface. + * @param \Jdenticon\Rendering\Rectangle $rect The outer bounds of the icon. + * @param \Jdenticon\IdenticonStyle $style The style of the icon. + * @param \Jdenticon\Rendering\ColorTheme $colorTheme A color theme + * specifying the colors to be used in the icon. + * @param string $hash The hash to be used as basis for the generated icon. + */ + protected function renderBackground( + \Jdenticon\Rendering\RendererInterface $renderer, + \Jdenticon\Rendering\Rectangle $rect, + \Jdenticon\IdenticonStyle $style, + \Jdenticon\Rendering\ColorTheme $colorTheme, + $hash) + { + $renderer->setBackgroundColor($style->getBackgroundColor()); + } + + /** + * Renders the foreground of an icon. + * + * @param \Jdenticon\Rendering\RendererInterface $renderer The renderer to + * be used for rendering the icon on the target surface. + * @param \Jdenticon\Rendering\Rectangle $rect The outer bounds of the icon. + * @param \Jdenticon\IdenticonStyle $style The style of the icon. + * @param \Jdenticon\Rendering\ColorTheme $colorTheme A color theme + * specifying the colors to be used in the icon. + * @param string $hash The hash to be used as basis for the generated icon. + */ + protected function renderForeground( + \Jdenticon\Rendering\RendererInterface $renderer, + \Jdenticon\Rendering\Rectangle $rect, + \Jdenticon\IdenticonStyle $style, + \Jdenticon\Rendering\ColorTheme $colorTheme, + $hash) + { + // Ensure rect is quadratic and a multiple of the cell count + $normalizedRect = $this->normalizeRectangle($rect); + $cellSize = $normalizedRect->width / $this->getCellCount(); + + foreach ($this->getShapes($colorTheme, $hash) as $shape) { + $rotation = $shape->startRotationIndex; + + $renderer->beginShape($shape->color); + + $positionCount = count($shape->positions); + for ($i = 0; $i + 1 < $positionCount; $i += 2) { + $renderer->setTransform(new Transform( + $normalizedRect->x + $shape->positions[$i + 0] * $cellSize, + $normalizedRect->y + $shape->positions[$i + 1] * $cellSize, + $cellSize, $rotation++ % 4)); + + $shape->definition->__invoke($renderer, $cellSize, $i / 2); + } + + $renderer->endShape(); + } + } + + /** + * Generates an identicon for the specified hash. + * + * @param \Jdenticon\Rendering\RendererInterface $renderer The renderer to + * be used for rendering the icon on the target surface. + * @param \Jdenticon\Rendering\Rectangle $rect The outer bounds of the icon. + * @param \Jdenticon\IdenticonStyle $style The style of the icon. + * @param string $hash The hash to be used as basis for the generated icon. + */ + public function generate( + \Jdenticon\Rendering\RendererInterface $renderer, + \Jdenticon\Rendering\Rectangle $rect, + \Jdenticon\IdenticonStyle $style, + $hash) + { + $hue = self::getHue($hash); + $colorTheme = new ColorTheme($hue, $style); + + $this->renderBackground($renderer, $rect, $style, $colorTheme, $hash); + $this->renderForeground($renderer, $rect, $style, $colorTheme, $hash); + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php b/vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php new file mode 100644 index 00000000..dbd6cf36 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php @@ -0,0 +1,296 @@ +Px = $x0; + $line->Py = $y0; + + $line->rx = $x1 - $x0; + $line->ry = $y1 - $y0; + + return $line; + } + + /** + * Moves the line to the right relative the direction vector. + * + * @param float $distance The number of pixels to move the line. + */ + public function moveRight($distance) + { + // Ortogonal direction vector + $rx = -$this->ry; + $ry = $this->rx; + + $multiplier = $distance / sqrt($rx * $rx + $ry * $ry); + + $this->Px += $rx * $multiplier; + $this->Py += $ry * $multiplier; + } + + /** + * Computes the point at which two lines intersect. + * + * @return Point|null + */ + public static function intersection( + ImagickRendererLine $l1, + ImagickRendererLine $l2 + ) { + $rs = $l1->rx * $l2->ry - $l1->ry * $l2->rx; + + if ($rs == 0) { + return null; + } + + $u = (($l2->Px - $l1->Px) * $l1->ry - ($l2->Py - $l1->Py) * $l1->rx) / $rs; + + return new Point( + $l2->Px + $u * $l2->rx, + $l2->Py + $u * $l2->ry + ); + } + + /** + * X coordiate of a point on the line. + * @var float + */ + public $Px; + /** + * Y coordiate of a point on the line. + * @var float + */ + public $Py; + + /** + * X component of the direction vector. + * @var float + */ + public $rx; + /** + * Y component of the direction vector. + * @var float + */ + public $ry; +} + +/** + * Renders icons as PNG using ImageMagick. + * + * Unfortunately the ImageMagick vector renderer has a lot of quirks that + * we need to accomodate. The most obvious is that the renderer always render + * all polygons 1/2 pixel too large. This behavior is documented here: + * http://www.imagemagick.org/Usage/draw/#bounds + * + * To prevent this we shrink all polygons with 1/2 pixels before passing them + * to ImageMagick. + * + * Another quirk is that if the polygon including the 1/2 pixel invisible border + * align perfectly to the pixel grid, white pixels will appear near edge + * intersections. Paths containing arcs will sometimes appear with horizontal + * lines drawn to the right side of the image. + * + * To prevent this (in most cases) we add 0.00013 to all coordinates. + * + */ +class ImagickRenderer extends AbstractRenderer +{ + private $draw; + private $polygon; + private $width; + private $height; + + /** + * This constant is added to all coordinates to avoid white pixels + * that sometimes appear near edge intersections when a polygon including + * its 1/2 invisible border is perfectly aligned to the pixel grid. + */ + const PREVENT_WHITE_PIXELS_OFFSET = -0.00013; + + /** + * Creates an instance of the class ImagickRenderer. + * + * @param int $width The width of the icon in pixels. + * @param int $height The height of the icon in pixels. + */ + public function __construct($width, $height) + { + parent::__construct(); + $this->draw = new \ImagickDraw(); + $this->draw->setStrokeWidth(1); + + $this->width = $width; + $this->height = $height; + } + + /** + * Gets the MIME type of the renderer output. + * + * @return string + */ + public function getMimeType() + { + return 'image/png'; + } + + /** + * Adds a circle without translating its coordinates. + * + * @param float $x The x-coordinate of the bounding rectangle + * upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle + * upper-left corner. + * @param float $size The size of the bounding rectangle. + * @param bool $counterClockwise If true the circle will be drawn + * counter clockwise. + */ + protected function addCircleNoTransform($x, $y, $size, $counterClockwise) + { + if ($counterClockwise) { + $x -= $size + 0.5; + $y -= 1; + } else { + $size -= 1; + $y -= 0.5; + } + + $radius = $size / 2; + $this->draw->pathMoveToAbsolute( + $x + $size + self::PREVENT_WHITE_PIXELS_OFFSET, + $y + $radius + self::PREVENT_WHITE_PIXELS_OFFSET); + $this->draw->pathEllipticArcRelative($radius, $radius, + M_PI * 2, true, $counterClockwise, 0, 1); + $this->draw->pathClose(); + } + + /** + * Adds a polygon without translating its coordinates. + * + * @param array $points An array of the points that the polygon consists of. + */ + protected function addPolygonNoTransform($points) + { + $firstPoint = $points[0]; + $lastPoint = end($points); + + // Ensure polygon is closed + if ($firstPoint->x != $lastPoint->x || + $firstPoint->y != $lastPoint->y + ) { + $points[] = $firstPoint; + } + + // Determine if polygon is an outer ring + // (source: https://stackoverflow.com/a/1165943) + $sum = 0; + $previousPoint = null; + + foreach ($points as $point) { + if ($previousPoint !== null) { + $sum += ($point->x - $previousPoint->x) * ($point->y + $previousPoint->y); + } + $previousPoint = $point; + } + + $isOuterRing = $sum < 0; + + // ImageMagick draws all polygons 1 pixel too large. To prevent this, + // shrink polygons by 1 pixel. + $lines = array(); + $previousPoint = null; + + // Transform all edges to lines. + foreach ($points as $point) { + if ($previousPoint !== null) { + $lines[] = $line = ImagickRendererLine::fromVector( + $previousPoint->x, $previousPoint->y, + $point->x, $point->y + ); + + // ImageMagick draws a 1px border along the outer ring. To + // prevent the border overlaps inner rings too close to the + // outer ring, only inflate inner rings by 1/4 pixel. + $line->moveRight($isOuterRing ? 0.5 : 0.25); + } + $previousPoint = $point; + } + + $first = true; + $previousLine = end($lines); + + // Reconstruct point array from line intersections and draw the polygon + foreach ($lines as $line) { + $points[] = $point = ImagickRendererLine::intersection($previousLine, $line); + + // Subtract 1/2 pixel to align the shapes to the pixel grid. + if ($first) { + $this->draw->pathMoveToAbsolute( + $point->x - 0.5 + self::PREVENT_WHITE_PIXELS_OFFSET, + $point->y - 0.5 + self::PREVENT_WHITE_PIXELS_OFFSET); + + $first = false; + } else { + $this->draw->pathLineToAbsolute( + $point->x - 0.5 + self::PREVENT_WHITE_PIXELS_OFFSET, + $point->y - 0.5 + self::PREVENT_WHITE_PIXELS_OFFSET); + } + + $previousLine = $line; + } + + $this->draw->pathClose(); + } + + /** + * Begins a new shape. The shape should be ended with a call to endShape. + * + * @param \Jdenticon\Color $color The color of the shape. + */ + public function beginShape(\Jdenticon\Color $color) + { + $this->draw->setFillColor($color->__toString()); + $this->draw->pathStart(); + } + + /** + * Ends the currently drawn shape. + */ + public function endShape() + { + $this->draw->pathFinish(); + } + + /** + * Renders this image as a PNG data stream. + * + * @return string + */ + public function getData() + { + $imagick = new \Imagick(); + $imagick->newImage($this->width, $this->height, $this->backgroundColor->__toString()); + $imagick->setImageFormat('png'); + + if (method_exists($imagick, 'setImageProperty')) { + $imagick->setImageProperty('Software', 'Jdenticon'); + } else { + $imagick->setImageAttribute('Software', 'Jdenticon'); + } + + $imagick->drawImage($this->draw); + return $imagick->getImageBlob(); + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php b/vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php new file mode 100644 index 00000000..10c816be --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php @@ -0,0 +1,123 @@ +canvas = new Canvas($width, $height); + $this->ctx = $this->canvas->getContext(); + } + + /** + * Gets the MIME type of the renderer output. + * + * @return string + */ + public function getMimeType() + { + return 'image/png'; + } + + /** + * Adds a circle without translating its coordinates. + * + * @param float $x The x-coordinate of the bounding rectangle + * upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle + * upper-left corner. + * @param float $size The size of the bounding rectangle. + * @param bool $counterClockwise If true the circle will be drawn + * counter clockwise. + */ + protected function addCircleNoTransform($x, $y, $size, $counterClockwise) + { + $radius = $size / 2; + $this->ctx->moveTo($x + $size, $y + $radius); + $this->ctx->arc( + $x + $radius, $y + $radius, + $radius, 0, M_PI * 2, + $counterClockwise); + $this->ctx->closePath(); + } + + /** + * Adds a polygon without translating its coordinates. + * + * @param array $points An array of the points that the polygon consists of. + */ + protected function addPolygonNoTransform($points) + { + $pointCount = count($points); + $this->ctx->moveTo($points[0]->x, $points[0]->y); + for ($i = 1; $i < $pointCount; $i++) { + $this->ctx->lineTo($points[$i]->x, $points[$i]->y); + } + $this->ctx->closePath(); + } + + /** + * Sets the background color of the icon. + * + * @param \Jdenticon\Color $color The background color. + */ + public function setBackgroundColor(\Jdenticon\Color $color) + { + parent::setBackgroundColor($color); + $this->canvas->backColor = $this->backgroundColor->toRgba(); + } + + /** + * Begins a new shape. The shape should be ended with a call to endShape. + * + * @param \Jdenticon\Color $color The color of the shape. + */ + public function beginShape(\Jdenticon\Color $color) + { + $this->ctx->fillStyle = $color->toRgba(); + $this->ctx->beginPath(); + } + + /** + * Ends the currently drawn shape. + */ + public function endShape() + { + $this->ctx->fill(); + } + + /** + * Gets the output from the renderer. + * + * @return string + */ + public function getData() + { + return $this->canvas->toPng(array('Software' => 'Jdenticon')); + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/Point.php b/vendor/jdenticon/jdenticon/src/Rendering/Point.php new file mode 100644 index 00000000..020845e6 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/Point.php @@ -0,0 +1,54 @@ +x = $x; + $this->y = $y; + } + + /** + * The X coordinate of this point. + * + * @var float + */ + public $x; + + /** + * The Y coordinate of this point. + * + * @var float + */ + public $y; + + /** + * Gets a string representation of the point. + * + * @return string + */ + public function __toString() + { + return $this->x + ", " + $this->y; + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php b/vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php new file mode 100644 index 00000000..27056c65 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php @@ -0,0 +1,60 @@ +x = $x; + $this->y = $y; + $this->width = $width; + $this->height = $height; + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php b/vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php new file mode 100644 index 00000000..2e579e0c --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php @@ -0,0 +1,141 @@ +dataString = ''; + } + + /** + * Adds a circle to the SVG. + * + * @param float $x X coordinate of the left side of the containing rectangle. + * @param float $y Y coordinate of the top side of the containing rectangle. + * @param float $size The diameter of the circle. + * @param bool $counterClockwise If true the circle will be drawn counter + * clockwise. This affects the rendering since the evenodd filling rule + * is used by Jdenticon. + */ + public function addCircle($x, $y, $size, $counterClockwise) + { + $sweepFlag = $counterClockwise ? '0' : '1'; + $radiusAsString = number_format($size / 2, 2, '.', ''); + + $this->dataString .= + 'M'. number_format($x, 2, '.', '') .' '. + number_format($y + $size / 2, 2, '.', ''). + 'a'. $radiusAsString .','. $radiusAsString .' 0 1,'. + $sweepFlag .' '. number_format($size, 2, '.', '') .',0'. + 'a'. $radiusAsString .','. $radiusAsString .' 0 1,'. + $sweepFlag .' '. number_format(-$size, 2, '.', '') .',0'; + } + + /** + * Adds a polygon to the SVG. + * + * @param array(\Jdenticon\Rendering\Point) $points The corners of the + * polygon. + */ + public function addPolygon($points) + { + $pointCount = count($points); + + $this->dataString .= 'M'. + number_format($points[0]->x, 2, '.', '') .' '. + number_format($points[0]->y, 2, '.', ''); + + for ($i = 1; $i < $pointCount; $i++) { + $this->dataString .= 'L'. + number_format($points[$i]->x, 2, '.', '') .' '. + number_format($points[$i]->y, 2, '.', ''); + } + + $this->dataString .= 'Z'; + } + + /** + * Gets the path as a SVG path string. + * + * @return string + */ + public function __toString() + { + return $this->dataString; + } +} + diff --git a/vendor/jdenticon/jdenticon/src/Rendering/SvgRenderer.php b/vendor/jdenticon/jdenticon/src/Rendering/SvgRenderer.php new file mode 100644 index 00000000..3a1df854 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/SvgRenderer.php @@ -0,0 +1,133 @@ +width = $width; + $this->height = $height; + } + + /** + * Gets the MIME type of the renderer output. + * + * @return string + */ + public function getMimeType() + { + return 'image/svg+xml'; + } + + /** + * Adds a circle without translating its coordinates. + * + * @param float $x The x-coordinate of the bounding rectangle + * upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle + * upper-left corner. + * @param float $size The size of the bounding rectangle. + * @param bool $counterClockwise If true the circle will be drawn + * counter clockwise. + */ + protected function addCircleNoTransform($x, $y, $size, $counterClockwise) + { + $this->path->addCircle($x, $y, $size, $counterClockwise); + } + + /** + * Adds a polygon without translating its coordinates. + * + * @param array $points An array of the points that the polygon consists of. + */ + protected function addPolygonNoTransform($points) + { + $this->path->addPolygon($points); + } + + /** + * Begins a new shape. The shape should be ended with a call to endShape. + * + * @param \Jdenticon\Color $color The color of the shape. + */ + public function beginShape(\Jdenticon\Color $color) + { + $colorString = $color->toHexString(6); + + if (isset($this->pathsByColor[$colorString])) { + $this->path = $this->pathsByColor[$colorString]; + } else { + $this->path = new SvgPath(); + $this->pathsByColor[$colorString] = $this->path; + } + } + + /** + * Ends the currently drawn shape. + */ + public function endShape() + { + } + + /** + * Generates an SVG string of the renderer output. + * + * @param bool $fragment If true an SVG string without the root svg element + * will be rendered. + */ + public function getData($fragment = false) + { + $svg = ''; + $widthAsString = number_format($this->width, 0, '.', ''); + $heightAsString = number_format($this->height, 0, '.', ''); + + if (!$fragment) { + $svg .= ''; + } + + if ($this->backgroundColor->a > 0) { + $opacity = (float)$this->backgroundColor->a / 255; + $svg .= ''; + } + + foreach ($this->pathsByColor as $color => $path) { + $svg .= ""; + } + + if (!$fragment) { + $svg .= ''; + } + + return $svg; + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/Transform.php b/vendor/jdenticon/jdenticon/src/Rendering/Transform.php new file mode 100644 index 00000000..f93de626 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/Transform.php @@ -0,0 +1,79 @@ +x = $x; + $this->y = $y; + $this->size = $size; + $this->rotation = $rotation; + } + + /** + * Gets a noop transform. + * + * @return \Jdenticon\Rendering\Transform + */ + public static function getEmpty() + { + return new Transform(0, 0, 0, 0); + } + + /** + * Transforms the specified point based on the translation and rotation + * specification for this Transform. + * + * @param float $x x-coordinate + * @param float $y y-coordinate + * @param float $width The width of the transformed rectangle. If greater + * than 0, this will ensure the returned point is of the upper left + * corner of the transformed rectangle. + * @param float $height The height of the transformed rectangle. If greater + * than 0, this will ensure the returned point is of the upper left + * corner of the transformed rectangle. + * @return \Jdenticon\Rendering\Point + */ + public function transformPoint($x, $y, $width = 0, $height = 0) + { + $right = $this->x + $this->size; + $bottom = $this->y + $this->size; + + switch ($this->rotation) { + case 1: return new Point($right - $y - $height, $this->y + $x); + case 2: return new Point($right - $x - $width, $bottom - $y - $height); + case 3: return new Point($this->x + $y, $bottom - $x - $width); + default: return new Point($this->x + $x, $this->y + $y); + } + } +} diff --git a/vendor/jdenticon/jdenticon/src/Rendering/TriangleDirection.php b/vendor/jdenticon/jdenticon/src/Rendering/TriangleDirection.php new file mode 100644 index 00000000..fb1fff91 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Rendering/TriangleDirection.php @@ -0,0 +1,35 @@ +definition = $definition; + $this->color = $color; + $this->positions = $positions; + $this->startRotationIndex = $startRotationIndex; + } +} diff --git a/vendor/jdenticon/jdenticon/src/Shapes/ShapeCategory.php b/vendor/jdenticon/jdenticon/src/Shapes/ShapeCategory.php new file mode 100644 index 00000000..202de814 --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Shapes/ShapeCategory.php @@ -0,0 +1,71 @@ +colorIndex = $colorIndex; + $this->shapes = $shapes; + $this->shapeIndex = $shapeIndex; + $this->rotationIndex = $rotationIndex; + $this->positions = $positions; + } +} + diff --git a/vendor/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php b/vendor/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php new file mode 100644 index 00000000..8278be0f --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php @@ -0,0 +1,243 @@ +addTriangle(0, 0, $cell, $cell, 0); + }, + function ($renderer, $cell, $index) + { + $renderer->addTriangle(0, $cell / 2, $cell, $cell / 2, 0); + }, + function ($renderer, $cell, $index) + { + $renderer->addRhombus(0, 0, $cell, $cell); + }, + function ($renderer, $cell, $index) + { + $m = $cell / 6; + $renderer->addCircle($m, $m, $cell - 2 * $m); + } + ); + } + + private static function createCenterShapes() + { + return array( + function ($renderer, $cell, $index) + { + $k = $cell * 0.42; + $renderer->addPolygon(array( + new Point(0, 0), + new Point($cell, 0), + new Point($cell, $cell - $k * 2), + new Point($cell - $k, $cell), + new Point(0, $cell) + )); + }, + function ($renderer, $cell, $index) + { + $w = (int)($cell * 0.5); + $h = (int)($cell * 0.8); + $renderer->addTriangle( + $cell - $w, 0, $w, $h, + TriangleDirection::NORTH_EAST); + }, + function ($renderer, $cell, $index) + { + $s = (int)($cell / 3); + $renderer->addRectangle($s, $s, $cell - $s, $cell - $s); + }, + function ($renderer, $cell, $index) + { + $tmp = $cell * 0.1; + + if ($tmp > 1) { + // large icon => truncate decimals + $inner = (int)$tmp; + } elseif ($tmp > 0.5) { + // medium size icon => fixed width + $inner = 1; + } else { + // small icon => anti-aliased border + $inner = $tmp; + } + + // Use fixed outer border widths in small icons to ensure + // the border is drawn + if ($cell < 6) { + $outer = 1; + } elseif ($cell < 8) { + $outer = 2; + } else { + $outer = (int)($cell / 4); + } + + $renderer->addRectangle( + $outer, $outer, + $cell - $inner - $outer, $cell - $inner - $outer); + }, + function ($renderer, $cell, $index) + { + $m = (int)($cell * 0.15); + $s = (int)($cell * 0.5); + $renderer->addCircle($cell - $s - $m, $cell - $s - $m, $s); + }, + function ($renderer, $cell, $index) + { + $inner = $cell * 0.1; + $outer = $inner * 4; + + // Align edge to nearest pixel in large icons + if ($outer > 3) { + $outer = (int)$outer; + } + + $renderer->addRectangle(0, 0, $cell, $cell); + $renderer->addPolygon(array( + new Point($outer, $outer), + new Point($cell - $inner, $outer), + new Point($outer + ($cell - $outer - $inner) / 2, + $cell - $inner) + ), true); + }, + function ($renderer, $cell, $index) + { + $renderer->addPolygon(array( + new Point(0, 0), + new Point($cell, 0), + new Point($cell, $cell * 0.7), + new Point($cell * 0.4, $cell * 0.4), + new Point($cell * 0.7, $cell), + new Point(0, $cell) + )); + }, + function ($renderer, $cell, $index) + { + $renderer->addTriangle( + $cell / 2, $cell / 2, $cell / 2, $cell / 2, + TriangleDirection::SOUTH_EAST); + }, + function ($renderer, $cell, $index) + { + $renderer->addPolygon(array( + new Point(0, 0), + new Point($cell, 0), + new Point($cell, $cell / 2), + new Point($cell / 2, $cell), + new Point(0, $cell) + )); + }, + function ($renderer, $cell, $index) + { + $tmp = $cell * 0.14; + + if ($cell < 8) { + // small icon => anti-aliased border + $inner = $tmp; + } else { + // large icon => truncate decimals + $inner = (int)$tmp; + } + + // Use fixed outer border widths in small icons to ensure + // the border is drawn + if ($cell < 4) { + $outer = 1; + } elseif ($cell < 6) { + $outer = 2; + } else { + $outer = (int)($cell * 0.35); + } + + $renderer->addRectangle(0, 0, $cell, $cell); + $renderer->addRectangle( + $outer, $outer, + $cell - $outer - $inner, $cell - $outer - $inner, true); + }, + function ($renderer, $cell, $index) + { + $inner = $cell * 0.12; + $outer = $inner * 3; + + $renderer->addRectangle(0, 0, $cell, $cell); + $renderer->addCircle($outer, $outer, $cell - $inner - $outer, + true); + }, + function ($renderer, $cell, $index) + { + $renderer->addTriangle( + $cell / 2, $cell / 2, $cell / 2, $cell / 2, + TriangleDirection::SOUTH_EAST); + }, + function ($renderer, $cell, $index) + { + $m = $cell * 0.25; + + $renderer->addRectangle(0, 0, $cell, $cell); + $renderer->addRhombus($m, $m, $cell - $m, $cell - $m, true); + }, + function ($renderer, $cell, $index) + { + $m = $cell * 0.4; + $s = $cell * 1.2; + + if ($index != 0) { + $renderer->addCircle($m, $m, $s); + } + } + ); + } +} diff --git a/vendor/jdenticon/jdenticon/src/Shapes/ShapePosition.php b/vendor/jdenticon/jdenticon/src/Shapes/ShapePosition.php new file mode 100644 index 00000000..9c780fce --- /dev/null +++ b/vendor/jdenticon/jdenticon/src/Shapes/ShapePosition.php @@ -0,0 +1,45 @@ +x = $x; + $this->y = $y; + } +} +