Jelajahi Sumber

Merge pull request #49 from MaximilianKresse/fpdfOutput

Added Fpdf output
smiley 5 tahun lalu
induk
melakukan
5e6c0290b2
5 mengubah file dengan 138 tambahan dan 6 penghapusan
  1. 2 1
      README.md
  2. 4 2
      composer.json
  3. 46 0
      examples/fpdf.php
  4. 80 0
      src/Output/QRFpdf.php
  5. 6 3
      src/QRCode.php

+ 2 - 1
README.md

@@ -39,7 +39,7 @@ A documentation created with [phpDocumentor](https://www.phpdoc.org/) can be fou
 ### Requirements
 - PHP 7.4+
   - `ext-mbstring`
-  - optional: `ext-json`, `ext-gd`, `ext-imagick`
+  - optional: `ext-json`, `ext-gd`, `ext-imagick`, `setasign/fpdf` (for QR fpdf output module)
 
 ### Installation
 **requires [composer](https://getcomposer.org)**
@@ -301,6 +301,7 @@ name | description
 `OUTPUT_IMAGE_PNG`, `OUTPUT_IMAGE_JPG`, `OUTPUT_IMAGE_GIF` | `QROptions::$outputType` image
 `OUTPUT_STRING_JSON`, `OUTPUT_STRING_TEXT` | `QROptions::$outputType` string
 `OUTPUT_IMAGICK` | `QROptions::$outputType` ImageMagick
+`OUTPUT_FPDF` | `QROptions::$outputType` string
 `OUTPUT_CUSTOM` | `QROptions::$outputType`, requires `QROptions::$outputInterface`
 `ECC_L`, `ECC_M`, `ECC_Q`, `ECC_H`, | ECC-Level: 7%, 15%, 25%, 30%  in `QROptions::$eccLevel`
 `DATA_NUMBER`, `DATA_ALPHANUM`, `DATA_BYTE`, `DATA_KANJI` | `QRDataInterface::$datamode`

+ 4 - 2
composer.json

@@ -30,10 +30,12 @@
 	},
 	"require-dev": {
 		"phpunit/phpunit": "^9.1",
-		"phan/phan": "^2.7"
+		"phan/phan": "^2.7",
+		"setasign/fpdf": "^1.8"
 	},
 	"suggest": {
-		"chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps."
+		"chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.",
+		"setasign/fpdf": "Required to use the QR FPDF output."
 	},
 	"autoload": {
 		"psr-4": {

+ 46 - 0
examples/fpdf.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+
+$options = new QROptions([
+    'version'      => 7,
+    'outputType'   => QRCode::OUTPUT_FPDF,
+    'eccLevel'     => QRCode::ECC_L,
+    'scale'        => 5,
+    'moduleValues' => [
+        // finder
+        1536 => [0, 63, 255], // dark (true)
+        6    => [255, 255, 255], // light (false), white is the transparency color and is enabled by default
+        // alignment
+        2560 => [255, 0, 255],
+        10   => [255, 255, 255],
+        // timing
+        3072 => [255, 0, 0],
+        12   => [255, 255, 255],
+        // format
+        3584 => [67, 191, 84],
+        14   => [255, 255, 255],
+        // version
+        4096 => [62, 174, 190],
+        16   => [255, 255, 255],
+        // data
+        1024 => [0, 0, 0],
+        4    => [255, 255, 255],
+        // darkmodule
+        512  => [0, 0, 0],
+        // separator
+        8    => [255, 255, 255],
+        // quietzone
+        18   => [255, 255, 255],
+    ],
+]);
+
+\header('Content-type: application/pdf');
+
+echo (new QRCode($options))->render($data);

+ 80 - 0
src/Output/QRFpdf.php

@@ -0,0 +1,80 @@
+<?php
+
+declare(strict_types=1);
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\Data\QRMatrix;
+use chillerlan\Settings\SettingsContainerInterface;
+
+/**
+ * QRFpdf output module (requires fpdf)
+ *
+ * @see https://github.com/Setasign/FPDF
+ * @see http://www.fpdf.org/
+ */
+class QRFpdf extends QROutputAbstract
+{
+    public function __construct(SettingsContainerInterface $options, QRMatrix $matrix)
+    {
+        parent::__construct($options, $matrix);
+
+        if (!\class_exists(\FPDF::class)) {
+            throw new \BadMethodCallException(
+                'The QRFpdf output requires FPDF as dependency but the class "\FPDF" couldn\'t be found.'
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    protected function setModuleValues(): void
+    {
+        foreach ($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue) {
+            $v = $this->options->moduleValues[$M_TYPE] ?? null;
+
+            if (!\is_array($v) || \count($v) < 3) {
+                $this->moduleValues[$M_TYPE] = $defaultValue
+                    ? [0, 0, 0]
+                    : [255, 255, 255];
+            } else {
+                $this->moduleValues[$M_TYPE] = \array_values($v);
+            }
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function dump(string $file = null): string
+    {
+        $file ??= $this->options->cachefile;
+
+        $fpdf = new \FPDF('P', 'pt', [$this->length, $this->length]);
+        $fpdf->AddPage();
+
+        $prevColor = null;
+        foreach ($this->matrix->matrix() as $y => $row) {
+            foreach ($row as $x => $M_TYPE) {
+                /**
+                 * @var int $M_TYPE
+                 */
+                $color = $this->moduleValues[$M_TYPE];
+                if ($prevColor === null || $prevColor !== $color) {
+                    $fpdf->SetFillColor(...$color);
+                    $prevColor = $color;
+                }
+                $fpdf->Rect($x * $this->scale, $y * $this->scale, 1 * $this->scale, 1 * $this->scale, 'F');
+            }
+        }
+
+        $pdfData = $fpdf->Output('S');
+
+        if ($file !== null) {
+            $this->saveToFile($pdfData, $file);
+        }
+
+        return $pdfData;
+    }
+}

+ 6 - 3
src/QRCode.php

@@ -15,9 +15,7 @@ namespace chillerlan\QRCode;
 use chillerlan\QRCode\Data\{
 	AlphaNum, Byte, Kanji, MaskPatternTester, Number, QRCodeDataException, QRDataInterface, QRMatrix
 };
-use chillerlan\QRCode\Output\{
-	QRCodeOutputException, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString
-};
+use chillerlan\QRCode\Output\{QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString};
 use chillerlan\Settings\SettingsContainerInterface;
 
 use function call_user_func_array, class_exists, in_array, mb_internal_encoding, ord, strlen, strtolower, str_split;
@@ -107,6 +105,8 @@ class QRCode{
 	/** @var string */
 	public const OUTPUT_IMAGICK     = 'imagick';
 	/** @var string */
+	public const OUTPUT_FPDF        = 'fpdf';
+	/** @var string */
 	public const OUTPUT_CUSTOM      = 'custom';
 
 	/**
@@ -131,6 +131,9 @@ class QRCode{
 		QRImagick::class => [
 			self::OUTPUT_IMAGICK,
 		],
+		QRFpdf::class => [
+			self::OUTPUT_FPDF
+		]
 	];
 
 	/**