-
Notifications
You must be signed in to change notification settings - Fork 407
[FEATURE] Data,Refinery: add QR code support #11391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * This file is part of ILIAS, a powerful learning management system | ||
| * published by ILIAS open source e-Learning e.V. | ||
| * | ||
| * ILIAS is licensed with the GPL-3.0, | ||
| * see https://www.gnu.org/licenses/gpl-3.0.en.html | ||
| * You should have received a copy of said license along with the | ||
| * source code, too. | ||
| * | ||
| * If this is not the case or you just want to try ILIAS, you'll find | ||
| * us at: | ||
| * https://www.ilias.de | ||
| * https://github.com/ILIAS-eLearning | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace ILIAS\Data\QR; | ||
|
|
||
| /** | ||
| * Error correction levels as defined by ISO/IEC 18004. | ||
| * | ||
| * Each level specifies the percentage of codewords that can be | ||
| * restored if the QR code is damaged or partially obscured. | ||
| * Please note that increasing the error correction level will | ||
| * decrease the data capacity of its payload. | ||
| * | ||
| * @see https://www.qrcode.com/en/about/error_correction.html | ||
| */ | ||
| enum ErrorCorrectionLevel: string | ||
| { | ||
| /** ~7% of codewords can be restored. */ | ||
| case LOW = 'L'; | ||
|
|
||
| /** ~15% of codewords can be restored (most fequently used). */ | ||
| case MEDIUM = 'M'; | ||
|
|
||
| /** ~25% of codewords can be restored. */ | ||
| case QUARTILE = 'Q'; | ||
|
|
||
| /** ~30% of codewords can be restored. */ | ||
| case HIGH = 'H'; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * This file is part of ILIAS, a powerful learning management system | ||
| * published by ILIAS open source e-Learning e.V. | ||
| * | ||
| * ILIAS is licensed with the GPL-3.0, | ||
| * see https://www.gnu.org/licenses/gpl-3.0.en.html | ||
| * You should have received a copy of said license along with the | ||
| * source code, too. | ||
| * | ||
| * If this is not the case or you just want to try ILIAS, you'll find | ||
| * us at: | ||
| * https://www.ilias.de | ||
| * https://github.com/ILIAS-eLearning | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace ILIAS\Data; | ||
|
|
||
| /** | ||
| * Data transfer object that carries the raw SVG data as a string, | ||
| * created from trusted sources. This object is merely a type as | ||
| * a mean to talk about SVG's and pass them between different layers | ||
| * of the system, it does not validate whether the SVG is valid or | ||
| * not. | ||
| */ | ||
| readonly class SVG implements \Stringable | ||
| { | ||
| public function __construct( | ||
| protected string $raw_svg_string, | ||
| ) { | ||
| } | ||
|
|
||
| public function __toString(): string | ||
| { | ||
| return $this->raw_svg_string; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -20,12 +20,25 @@ | |||||
|
|
||||||
| namespace ILIAS\Refinery\URI; | ||||||
|
|
||||||
| use ILIAS\Refinery\Transformation; | ||||||
| use ILIAS\Refinery\Transformation as ITransformation; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| use ILIAS\Data\QR\ErrorCorrectionLevel; | ||||||
|
|
||||||
| class Group | ||||||
| { | ||||||
| public function toString(): Transformation | ||||||
| public function toString(): ITransformation | ||||||
| { | ||||||
| return new StringTransformation(); | ||||||
| return new Transformation\ToStringTransformation(); | ||||||
| } | ||||||
|
|
||||||
| public function toSvg( | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name |
||||||
| ErrorCorrectionLevel $error_correction_level = ErrorCorrectionLevel::MEDIUM, | ||||||
| int $size_in_px = 400, | ||||||
| ): ITransformation { | ||||||
| return new Transformation\ToSvgTransformation($error_correction_level, $size_in_px); | ||||||
| } | ||||||
|
|
||||||
| public function fromSvg(): ITransformation | ||||||
| { | ||||||
| return new Transformation\FromSvgTransformation(); | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * This file is part of ILIAS, a powerful learning management system | ||
| * published by ILIAS open source e-Learning e.V. | ||
| * | ||
| * ILIAS is licensed with the GPL-3.0, | ||
| * see https://www.gnu.org/licenses/gpl-3.0.en.html | ||
| * You should have received a copy of said license along with the | ||
| * source code, too. | ||
| * | ||
| * If this is not the case or you just want to try ILIAS, you'll find | ||
| * us at: | ||
| * https://www.ilias.de | ||
| * https://github.com/ILIAS-eLearning | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace ILIAS\Refinery\URI\Transformation; | ||
|
|
||
| use ILIAS\Refinery\DeriveApplyToFromTransform; | ||
| use ILIAS\Refinery\DeriveInvokeFromTransform; | ||
| use ILIAS\Refinery\Transformation; | ||
| use ILIAS\Data\SVG; | ||
|
|
||
| /** | ||
| * The {@see \ILIAS\Data\URI} does not support data URI yet, therefore | ||
| * this transformation currently returns a string. | ||
| */ | ||
| class FromSvgTransformation implements Transformation | ||
| { | ||
| use DeriveApplyToFromTransform; | ||
| use DeriveInvokeFromTransform; | ||
|
|
||
| protected const string SCHEME = 'data:'; | ||
| protected const string MIME_TYPE = 'image/svg+xml'; | ||
| protected const string ENCODING = 'base64'; | ||
|
|
||
| public function transform(mixed $from): string | ||
| { | ||
| if (!$from instanceof SVG) { | ||
| throw new \InvalidArgumentException("Argument must be of type " . SVG::class); | ||
| } | ||
|
|
||
| return self::SCHEME . self::MIME_TYPE . ';' . self::ENCODING . ',' . base64_encode($from->__toString()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * This file is part of ILIAS, a powerful learning management system | ||
| * published by ILIAS open source e-Learning e.V. | ||
| * | ||
| * ILIAS is licensed with the GPL-3.0, | ||
| * see https://www.gnu.org/licenses/gpl-3.0.en.html | ||
| * You should have received a copy of said license along with the | ||
| * source code, too. | ||
| * | ||
| * If this is not the case or you just want to try ILIAS, you'll find | ||
| * us at: | ||
| * https://www.ilias.de | ||
| * https://github.com/ILIAS-eLearning | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace ILIAS\Refinery\URI\Transformation; | ||
|
|
||
| use ILIAS\Refinery\DeriveApplyToFromTransform; | ||
| use ILIAS\Refinery\DeriveInvokeFromTransform; | ||
| use ILIAS\Refinery\Transformation; | ||
| use ILIAS\Data\QR\ErrorCorrectionLevel; | ||
| use ILIAS\Data\SVG; | ||
| use ILIAS\Data\URI; | ||
| use BaconQrCode as External; | ||
|
|
||
| class ToSvgTransformation implements Transformation | ||
| { | ||
| use DeriveApplyToFromTransform; | ||
| use DeriveInvokeFromTransform; | ||
|
|
||
| protected const string ENCODING = 'UTF-8'; | ||
|
|
||
| public function __construct( | ||
| protected ErrorCorrectionLevel $error_correction_level, | ||
| protected int $size_in_px, | ||
| ) { | ||
| $this->assertIntGreaterThanZero($size_in_px); | ||
| } | ||
|
|
||
| public function transform(mixed $from): SVG | ||
| { | ||
| if (!$from instanceof URI) { | ||
| throw new \InvalidArgumentException("Argument must be of type " . URI::class); | ||
| } | ||
|
|
||
| $writer = new External\Writer( | ||
| new External\Renderer\ImageRenderer( | ||
| new External\Renderer\RendererStyle\RendererStyle($this->size_in_px), | ||
| new External\Renderer\Image\SvgImageBackEnd(), | ||
| ), | ||
| ); | ||
|
|
||
| $raw_svg_string = $writer->writeString( | ||
| $from->__toString(), | ||
| self::ENCODING, | ||
| $this->mapErrorCorrectionLevel($this->error_correction_level), | ||
| ); | ||
|
|
||
| return new SVG($raw_svg_string); | ||
| } | ||
|
|
||
| protected function mapErrorCorrectionLevel(ErrorCorrectionLevel $level): External\Common\ErrorCorrectionLevel | ||
| { | ||
| return match ($level) { | ||
| ErrorCorrectionLevel::LOW => External\Common\ErrorCorrectionLevel::L(), | ||
| ErrorCorrectionLevel::MEDIUM => External\Common\ErrorCorrectionLevel::M(), | ||
| ErrorCorrectionLevel::QUARTILE => External\Common\ErrorCorrectionLevel::Q(), | ||
| ErrorCorrectionLevel::HIGH => External\Common\ErrorCorrectionLevel::H(), | ||
| }; | ||
| } | ||
|
|
||
| protected function assertIntGreaterThanZero(int $number): void | ||
| { | ||
| if (0 >= $number) { | ||
| throw new \InvalidArgumentException("Number must be greater than zero."); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * This file is part of ILIAS, a powerful learning management system | ||
| * published by ILIAS open source e-Learning e.V. | ||
| * | ||
| * ILIAS is licensed with the GPL-3.0, | ||
| * see https://www.gnu.org/licenses/gpl-3.0.en.html | ||
| * You should have received a copy of said license along with the | ||
| * source code, too. | ||
| * | ||
| * If this is not the case or you just want to try ILIAS, you'll find | ||
| * us at: | ||
| * https://www.ilias.de | ||
| * https://github.com/ILIAS-eLearning | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace ILIAS\Tests\Refinery\URI\Transformation; | ||
|
|
||
| use ILIAS\Refinery\URI\Transformation\FromSvgTransformation; | ||
| use PHPUnit\Framework\Attributes\Depends; | ||
| use PHPUnit\Framework\MockObject\MockObject; | ||
| use PHPUnit\Framework\TestCase; | ||
|
|
||
| class FromSvgTransformationTest extends TestCase | ||
| { | ||
| public function testTransformWithoutSvgInstance(): void | ||
| { | ||
| $transformation = new FromSvgTransformation(); | ||
| $this->expectException(\InvalidArgumentException::class); | ||
| $transformation->transform('<svg></svg>'); | ||
| } | ||
|
|
||
| public function testTransformWithSvgInstance(): void | ||
| { | ||
| $transformation = new FromSvgTransformation(); | ||
| $this->expectNotToPerformAssertions(); | ||
| $transformation->transform($this->createSvgMock()); | ||
| } | ||
|
|
||
| #[Depends('testTransformWithSvgInstance')] | ||
| public function testTransformResult(): void | ||
| { | ||
| $transformation = new FromSvgTransformation(); | ||
| $svg_mock = $this->createSvgMock(); | ||
| $result = $transformation->transform($svg_mock); | ||
| $this->assertIsString($result); | ||
| $this->assertStringStartsWith("data:image/svg+xml;base64,", $result); // ensure correct data uri format | ||
| $this->assertStringEndsWith(base64_encode($svg_mock->__toString()), $result); // ensure base64 encoded value | ||
| } | ||
|
|
||
| protected function createSvgMock(): \ILIAS\Data\SVG & MockObject | ||
| { | ||
| $svg_mock = $this->createMock(\ILIAS\Data\SVG::class); | ||
| $svg_mock->method('__toString')->willReturn('<svg></svg>'); | ||
| return $svg_mock; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.