diff --git a/composer.json b/composer.json index e6661d95b..9fe451d6b 100644 --- a/composer.json +++ b/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": { diff --git a/examples/fpdf.php b/examples/fpdf.php new file mode 100644 index 000000000..99ed8725b --- /dev/null +++ b/examples/fpdf.php @@ -0,0 +1,46 @@ + 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, 'example_fpdf.pdf'); diff --git a/src/Output/QRFpdf.php b/src/Output/QRFpdf.php new file mode 100644 index 000000000..22c8f25a0 --- /dev/null +++ b/src/Output/QRFpdf.php @@ -0,0 +1,74 @@ + $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; + } +} diff --git a/src/QRCode.php b/src/QRCode.php index f83bcc39e..906490950 100755 --- a/src/QRCode.php +++ b/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 + ] ]; /**