mirror of
https://github.com/chillerlan/php-qrcode.git
synced 2026-08-30 20:17:17 +00:00
✨ added PDF support (#49)
This commit is contained in:
@@ -34,8 +34,11 @@ namespaced, cleaned up, improved and other stuff.
|
|||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
- PHP 7.2+
|
- PHP 7.2+
|
||||||
- `ext-gd`, `ext-json`, `ext-mbstring`
|
- `ext-mbstring`
|
||||||
- optional `ext-imagick`
|
- optional:
|
||||||
|
- `ext-json`, `ext-gd`
|
||||||
|
- `ext-imagick` with [ImageMagick](https://imagemagick.org) installed
|
||||||
|
- [`setasign/fpdf`](https://github.com/setasign/fpdf) for the PDF output module
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
**requires [composer](https://getcomposer.org)**
|
**requires [composer](https://getcomposer.org)**
|
||||||
@@ -289,6 +292,7 @@ name | description
|
|||||||
`OUTPUT_IMAGE_PNG`, `OUTPUT_IMAGE_JPG`, `OUTPUT_IMAGE_GIF` | `QROptions::$outputType` image
|
`OUTPUT_IMAGE_PNG`, `OUTPUT_IMAGE_JPG`, `OUTPUT_IMAGE_GIF` | `QROptions::$outputType` image
|
||||||
`OUTPUT_STRING_JSON`, `OUTPUT_STRING_TEXT` | `QROptions::$outputType` string
|
`OUTPUT_STRING_JSON`, `OUTPUT_STRING_TEXT` | `QROptions::$outputType` string
|
||||||
`OUTPUT_IMAGICK` | `QROptions::$outputType` ImageMagick
|
`OUTPUT_IMAGICK` | `QROptions::$outputType` ImageMagick
|
||||||
|
`OUTPUT_FPDF` | `QROptions::$outputType` PDF, using [FPDF](https://github.com/setasign/fpdf)
|
||||||
`OUTPUT_CUSTOM` | `QROptions::$outputType`, requires `QROptions::$outputInterface`
|
`OUTPUT_CUSTOM` | `QROptions::$outputType`, requires `QROptions::$outputInterface`
|
||||||
`ECC_L`, `ECC_M`, `ECC_Q`, `ECC_H`, | ECC-Level: 7%, 15%, 25%, 30% in `QROptions::$eccLevel`
|
`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`
|
`DATA_NUMBER`, `DATA_ALPHANUM`, `DATA_BYTE`, `DATA_KANJI` | `QRDataInterface::$datamode`
|
||||||
|
|||||||
+4
-4
@@ -25,16 +25,16 @@
|
|||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.2",
|
"php": "^7.2",
|
||||||
"ext-gd": "*",
|
|
||||||
"ext-json": "*",
|
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"chillerlan/php-settings-container": "^1.2"
|
"chillerlan/php-settings-container": "^1.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^8.5"
|
"phpunit/phpunit": "^8.5",
|
||||||
|
"setasign/fpdf": "^1.8.2"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"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": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class QRFpdf
|
||||||
|
*
|
||||||
|
* https://github.com/chillerlan/php-qrcode/pull/49
|
||||||
|
*
|
||||||
|
* @filesource QRFpdf.php
|
||||||
|
* @created 03.06.2020
|
||||||
|
* @package chillerlan\QRCode\Output
|
||||||
|
* @author Maximilian Kresse
|
||||||
|
*
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace chillerlan\QRCode\Output;
|
||||||
|
|
||||||
|
use chillerlan\QRCode\Data\QRMatrix;
|
||||||
|
use chillerlan\QRCode\QRCodeException;
|
||||||
|
use chillerlan\Settings\SettingsContainerInterface;
|
||||||
|
use FPDF;
|
||||||
|
|
||||||
|
use function array_values, class_exists, count, is_array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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){
|
||||||
|
|
||||||
|
if(!class_exists(FPDF::class)){
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
throw new QRCodeException(
|
||||||
|
'The QRFpdf output requires FPDF as dependency but the class "\FPDF" couldn\'t be found.'
|
||||||
|
);
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($options, $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 = $file ?? $this->options->cachefile;
|
||||||
|
|
||||||
|
$fpdf = new FPDF('P', $this->options->fpdfMeasureUnit, [$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+5
-1
@@ -16,7 +16,7 @@ use chillerlan\QRCode\Data\{
|
|||||||
MaskPatternTester, QRCodeDataException, QRDataInterface, QRMatrix
|
MaskPatternTester, QRCodeDataException, QRDataInterface, QRMatrix
|
||||||
};
|
};
|
||||||
use chillerlan\QRCode\Output\{
|
use chillerlan\QRCode\Output\{
|
||||||
QRCodeOutputException, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString
|
QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString
|
||||||
};
|
};
|
||||||
use chillerlan\Settings\SettingsContainerInterface;
|
use chillerlan\Settings\SettingsContainerInterface;
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@ class QRCode{
|
|||||||
public const OUTPUT_STRING_JSON = 'json';
|
public const OUTPUT_STRING_JSON = 'json';
|
||||||
public const OUTPUT_STRING_TEXT = 'text';
|
public const OUTPUT_STRING_TEXT = 'text';
|
||||||
public const OUTPUT_IMAGICK = 'imagick';
|
public const OUTPUT_IMAGICK = 'imagick';
|
||||||
|
public const OUTPUT_FPDF = 'fpdf';
|
||||||
public const OUTPUT_CUSTOM = 'custom';
|
public const OUTPUT_CUSTOM = 'custom';
|
||||||
|
|
||||||
public const VERSION_AUTO = -1;
|
public const VERSION_AUTO = -1;
|
||||||
@@ -88,6 +89,9 @@ class QRCode{
|
|||||||
QRImagick::class => [
|
QRImagick::class => [
|
||||||
self::OUTPUT_IMAGICK,
|
self::OUTPUT_IMAGICK,
|
||||||
],
|
],
|
||||||
|
QRFpdf::class => [
|
||||||
|
self::OUTPUT_FPDF
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ use chillerlan\Settings\SettingsContainerAbstract;
|
|||||||
* @property string $imagickFormat
|
* @property string $imagickFormat
|
||||||
* @property string $imagickBG
|
* @property string $imagickBG
|
||||||
*
|
*
|
||||||
|
* @property string $fpdfMeasureUnit
|
||||||
|
*
|
||||||
* @property array $moduleValues
|
* @property array $moduleValues
|
||||||
*/
|
*/
|
||||||
class QROptions extends SettingsContainerAbstract{
|
class QROptions extends SettingsContainerAbstract{
|
||||||
|
|||||||
+23
-1
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
namespace chillerlan\QRCode;
|
namespace chillerlan\QRCode;
|
||||||
|
|
||||||
use function array_values, count, is_array, is_numeric, max, min, sprintf;
|
use function array_values, count, in_array, is_array, is_numeric, max, min, sprintf, strtolower;
|
||||||
|
|
||||||
trait QROptionsTrait{
|
trait QROptionsTrait{
|
||||||
|
|
||||||
@@ -241,6 +241,13 @@ trait QROptionsTrait{
|
|||||||
*/
|
*/
|
||||||
protected $imagickBG = null;
|
protected $imagickBG = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measurement unit for FPDF output: pt, mm, cm, in (defaults to "pt")
|
||||||
|
*
|
||||||
|
* @see \FPDF::__construct()
|
||||||
|
*/
|
||||||
|
protected $fpdfMeasureUnit = 'pt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module values map
|
* Module values map
|
||||||
*
|
*
|
||||||
@@ -367,4 +374,19 @@ trait QROptionsTrait{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the FPDF measurement unit
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
protected function set_fpdfMeasureUnit(string $unit):void{
|
||||||
|
$unit = strtolower($unit);
|
||||||
|
|
||||||
|
if(in_array($unit, ['cm', 'in', 'mm', 'pt'], true)){
|
||||||
|
$this->fpdfMeasureUnit = $unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo throw or ignore silently?
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class QRFpdfTest
|
||||||
|
*
|
||||||
|
* @filesource QRFpdfTest.php
|
||||||
|
* @created 03.06.2020
|
||||||
|
* @package chillerlan\QRCodeTest\Output
|
||||||
|
* @author smiley <smiley@chillerlan.net>
|
||||||
|
* @copyright 2020 smiley
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace chillerlan\QRCodeTest\Output;
|
||||||
|
|
||||||
|
use FPDF;
|
||||||
|
use chillerlan\QRCode\Output\{QRFpdf, QROutputInterface};
|
||||||
|
use chillerlan\QRCode\{QRCode, QROptions};
|
||||||
|
|
||||||
|
use function class_exists, substr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the QRFpdf output module
|
||||||
|
*/
|
||||||
|
class QRFpdfTest extends QROutputTestAbstract{
|
||||||
|
|
||||||
|
protected $FQCN = QRFpdf::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public function setUp():void{
|
||||||
|
|
||||||
|
if(!class_exists(FPDF::class)){
|
||||||
|
$this->markTestSkipped('FPDF not available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function testSetModuleValues():void{
|
||||||
|
|
||||||
|
$this->options->moduleValues = [
|
||||||
|
// data
|
||||||
|
1024 => [0, 0, 0],
|
||||||
|
4 => [255, 255, 255],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->outputInterface->dump();
|
||||||
|
|
||||||
|
$this::assertTrue(true); // tricking the code coverage
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function testRenderImage():void{
|
||||||
|
$type = QRCode::OUTPUT_FPDF;
|
||||||
|
|
||||||
|
$this->options->outputType = $type;
|
||||||
|
$this->outputInterface->dump($this::cachefile.$type);
|
||||||
|
|
||||||
|
// substr() to avoid CreationDate
|
||||||
|
$expected = substr(file_get_contents($this::cachefile.$type), 0, 2000);
|
||||||
|
$actual = substr($this->outputInterface->dump(), 0, 2000);
|
||||||
|
|
||||||
|
$this::assertSame($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user