diff --git a/examples/MyCustomOutput.php b/examples/MyCustomOutput.php index 4690b8528..4e4e5bcb4 100644 --- a/examples/MyCustomOutput.php +++ b/examples/MyCustomOutput.php @@ -18,6 +18,10 @@ use chillerlan\QRCode\Output\QROutputAbstract; */ class MyCustomOutput extends QROutputAbstract{ + protected function setModuleValues():void{ + // TODO: Implement setModuleValues() method. + } + public function dump(string $file = null){ $output = ''; diff --git a/src/Output/QRImage.php b/src/Output/QRImage.php index 51c89604b..a183e9a3e 100644 --- a/src/Output/QRImage.php +++ b/src/Output/QRImage.php @@ -12,85 +12,71 @@ namespace chillerlan\QRCode\Output; -use chillerlan\QRCode\{QRCode, Data\QRMatrix}; +use chillerlan\QRCode\QRCode; /** * Converts the matrix into images, raw or base64 output */ class QRImage extends QROutputAbstract{ - const transparencyTypes = [ + const TRANSPARENCY_TYPES = [ QRCode::OUTPUT_IMAGE_PNG, QRCode::OUTPUT_IMAGE_GIF, ]; protected $defaultMode = QRCode::OUTPUT_IMAGE_PNG; - protected $moduleValues = [ - // light - QRMatrix::M_DATA => [255, 255, 255], - QRMatrix::M_FINDER => [255, 255, 255], - QRMatrix::M_SEPARATOR => [255, 255, 255], - QRMatrix::M_ALIGNMENT => [255, 255, 255], - QRMatrix::M_TIMING => [255, 255, 255], - QRMatrix::M_FORMAT => [255, 255, 255], - QRMatrix::M_VERSION => [255, 255, 255], - QRMatrix::M_QUIETZONE => [255, 255, 255], - QRMatrix::M_TEST => [255, 255, 255], - // dark - QRMatrix::M_DARKMODULE << 8 => [0, 0, 0], - QRMatrix::M_DATA << 8 => [0, 0, 0], - QRMatrix::M_FINDER << 8 => [0, 0, 0], - QRMatrix::M_ALIGNMENT << 8 => [0, 0, 0], - QRMatrix::M_TIMING << 8 => [0, 0, 0], - QRMatrix::M_FORMAT << 8 => [0, 0, 0], - QRMatrix::M_VERSION << 8 => [0, 0, 0], - QRMatrix::M_TEST << 8 => [0, 0, 0], - ]; - /** * @see imagecreatetruecolor() * @var resource */ protected $image; - /** - * @var int - */ - protected $scale; - - /** - * @var int - */ - protected $length; - /** * @see imagecolorallocate() * @var int */ protected $background; + /** + * @return void + */ + 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); + } + + } + + } + /** * @param string|null $file * * @return string - * @throws \chillerlan\QRCode\Output\QRCodeOutputException */ public function dump(string $file = null):string{ + $this->image = imagecreatetruecolor($this->length, $this->length); + $this->background = imagecolorallocate($this->image, ...array_values($this->options->imageTransparencyBG)); - if($this->options->cachefile !== null && !is_writable(dirname($this->options->cachefile))){ - throw new QRCodeOutputException('Could not write data to cache file: '.$this->options->cachefile); + if((bool)$this->options->imageTransparent && in_array($this->options->outputType, $this::TRANSPARENCY_TYPES, true)){ + imagecolortransparent($this->image, $this->background); } - $this->setImage(); - - $moduleValues = is_array($this->options->moduleValues[$this->matrix::M_DATA]) - ? $this->options->moduleValues // @codeCoverageIgnore - : $this->moduleValues; + imagefilledrectangle($this->image, 0, 0, $this->length, $this->length, $this->background); foreach($this->matrix->matrix() as $y => $row){ - foreach($row as $x => $pixel){ - $this->setPixel($x, $y, imagecolorallocate($this->image, ...$moduleValues[$pixel])); + foreach($row as $x => $M_TYPE){ + $this->setPixel($x, $y, $this->moduleValues[$M_TYPE]); } } @@ -104,35 +90,20 @@ class QRImage extends QROutputAbstract{ } /** + * @param int $x + * @param int $y + * @param array $rgb + * * @return void */ - protected function setImage(){ - $this->scale = $this->options->scale; - $this->length = $this->moduleCount * $this->scale; - $this->image = imagecreatetruecolor($this->length, $this->length); - $this->background = imagecolorallocate($this->image, ...$this->options->imageTransparencyBG); - - if((bool)$this->options->imageTransparent && in_array($this->options->outputType, $this::transparencyTypes, true)){ - imagecolortransparent($this->image, $this->background); - } - - imagefilledrectangle($this->image, 0, 0, $this->length, $this->length, $this->background); - } - - /** - * @param int $x - * @param int $y - * @param int $color - * @return void - */ - protected function setPixel(int $x, int $y, int $color){ + protected function setPixel(int $x, int $y, array $rgb):void{ imagefilledrectangle( $this->image, $x * $this->scale, $y * $this->scale, - ($x + 1) * $this->scale - 1, - ($y + 1) * $this->scale - 1, - $color + ($x + 1) * $this->scale, + ($y + 1) * $this->scale, + imagecolorallocate($this->image, ...$rgb) ); } diff --git a/src/Output/QRMarkup.php b/src/Output/QRMarkup.php index 7e8aa4373..84bf1837d 100644 --- a/src/Output/QRMarkup.php +++ b/src/Output/QRMarkup.php @@ -21,6 +21,27 @@ class QRMarkup extends QROutputAbstract{ protected $defaultMode = QRCode::OUTPUT_MARKUP_SVG; + /** + * @return void + */ + protected function setModuleValues():void{ + + foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){ + $v = $this->options->moduleValues[$M_TYPE] ?? null; + + if(!is_string($v)){ + $this->moduleValues[$M_TYPE] = $defaultValue + ? $this->options->markupDark + : $this->options->markupLight; + } + else{ + $this->moduleValues[$M_TYPE] = trim(strip_tags($v), '\'"'); + } + + } + + } + /** * @return string|bool */ @@ -30,8 +51,8 @@ class QRMarkup extends QROutputAbstract{ foreach($this->matrix->matrix() as $row){ $html .= '
'; - foreach($row as $pixel){ - $html .= ''; + foreach($row as $M_TYPE){ + $html .= ''; } $html .= '
'.$this->options->eol; @@ -59,13 +80,7 @@ class QRMarkup extends QROutputAbstract{ .''.$this->options->svgDefs.'' .$this->options->eol; - foreach($this->options->moduleValues as $M_TYPE => $value){ - - // fallback - if(is_bool($value)){ - $value = $value ? '#000' : '#fff'; - } - + foreach($this->moduleValues as $M_TYPE => $value){ $path = ''; foreach($matrix as $y => $row){ diff --git a/src/Output/QROutputAbstract.php b/src/Output/QROutputAbstract.php index 57d803d07..d9e656ee5 100644 --- a/src/Output/QROutputAbstract.php +++ b/src/Output/QROutputAbstract.php @@ -16,7 +16,7 @@ use chillerlan\QRCode\{Data\QRMatrix, QRCode}; use chillerlan\Settings\SettingsContainerInterface; /** - * + * common output abstract */ abstract class QROutputAbstract implements QROutputInterface{ @@ -45,6 +45,21 @@ abstract class QROutputAbstract implements QROutputInterface{ */ protected $defaultMode; + /** + * @var int + */ + protected $scale; + + /** + * @var int + */ + protected $length; + + /** + * @var array + */ + protected $moduleValues; + /** * QROutputAbstract constructor. * @@ -55,6 +70,8 @@ abstract class QROutputAbstract implements QROutputInterface{ $this->options = $options; $this->matrix = $matrix; $this->moduleCount = $this->matrix->size(); + $this->scale = $this->options->scale; + $this->length = $this->moduleCount * $this->scale; $class = get_called_class(); @@ -62,8 +79,16 @@ abstract class QROutputAbstract implements QROutputInterface{ $this->outputMode = $this->options->outputType; } + $this->setModuleValues(); } + /** + * Sets the initial module values (clean-up & defaults) + * + * @return void + */ + abstract protected function setModuleValues():void; + /** * @see file_put_contents() * diff --git a/src/Output/QROutputInterface.php b/src/Output/QROutputInterface.php index 8ddc738c3..3cff7001b 100644 --- a/src/Output/QROutputInterface.php +++ b/src/Output/QROutputInterface.php @@ -12,11 +12,35 @@ namespace chillerlan\QRCode\Output; +use chillerlan\QRCode\Data\QRMatrix; + /** * Converts the data matrix into readable output */ interface QROutputInterface{ + const DEFAULT_MODULE_VALUES = [ + // light + QRMatrix::M_DATA => false, // 4 + QRMatrix::M_FINDER => false, // 6 + QRMatrix::M_SEPARATOR => false, // 8 + QRMatrix::M_ALIGNMENT => false, // 10 + QRMatrix::M_TIMING => false, // 12 + QRMatrix::M_FORMAT => false, // 14 + QRMatrix::M_VERSION => false, // 16 + QRMatrix::M_QUIETZONE => false, // 18 + QRMatrix::M_TEST => false, // 255 + // dark + QRMatrix::M_DARKMODULE << 8 => true, // 512 + QRMatrix::M_DATA << 8 => true, // 1024 + QRMatrix::M_FINDER << 8 => true, // 1536 + QRMatrix::M_ALIGNMENT << 8 => true, // 2560 + QRMatrix::M_TIMING << 8 => true, // 3072 + QRMatrix::M_FORMAT << 8 => true, // 3584 + QRMatrix::M_VERSION << 8 => true, // 4096 + QRMatrix::M_TEST << 8 => true, // 65280 + ]; + /** * @param string|null $file * diff --git a/src/Output/QRString.php b/src/Output/QRString.php index 231dfb5ff..dd7418804 100644 --- a/src/Output/QRString.php +++ b/src/Output/QRString.php @@ -21,6 +21,27 @@ class QRString extends QROutputAbstract{ protected $defaultMode = QRCode::OUTPUT_STRING_TEXT; + /** + * @return void + */ + protected function setModuleValues():void{ + + foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){ + $v = $this->options->moduleValues[$M_TYPE] ?? null; + + if(!is_string($v)){ + $this->moduleValues[$M_TYPE] = $defaultValue + ? $this->options->textDark + : $this->options->textLight; + } + else{ + $this->moduleValues[$M_TYPE] = $v; + } + + } + + } + /** * @return string */ @@ -30,17 +51,8 @@ class QRString extends QROutputAbstract{ foreach($this->matrix->matrix() as $row){ $r = []; - foreach($row as $col){ - $col = $this->options->moduleValues[$col]; - - // fallback - if(is_bool($col) || !is_string($col)){ - $col = $col - ? $this->options->textDark - : $this->options->textLight; - } - - $r[] = $col; + foreach($row as $M_TYPE){ + $r[] = $this->moduleValues[$M_TYPE]; } $str[] = implode('', $r); diff --git a/src/QROptions.php b/src/QROptions.php index 02b905ecb..f19b7a1f4 100644 --- a/src/QROptions.php +++ b/src/QROptions.php @@ -37,6 +37,9 @@ use chillerlan\Settings\SettingsContainerAbstract; * @property string $textDark * @property string $textLight * + * @property string $markupDark + * @property string $markupLight + * * @property bool $imageBase64 * @property bool $imageTransparent * @property array $imageTransparencyBG diff --git a/src/QROptionsTrait.php b/src/QROptionsTrait.php index 3346987cf..8994eb247 100644 --- a/src/QROptionsTrait.php +++ b/src/QROptionsTrait.php @@ -12,8 +12,6 @@ namespace chillerlan\QRCode; -use chillerlan\QRCode\Data\QRMatrix; - trait QROptionsTrait{ /** @@ -153,6 +151,20 @@ trait QROptionsTrait{ */ protected $textLight = '⭕'; + /** + * markup substitute for dark (CSS value) + * + * @var string + */ + protected $markupDark = '#000'; + + /** + * markup substitute for light (CSS value) + * + * @var string + */ + protected $markupLight = '#fff'; + /** * toggle base64 or raw image data * @@ -196,27 +208,7 @@ trait QROptionsTrait{ * * @var array */ - protected $moduleValues = [ - // light - QRMatrix::M_DATA => false, // 4 - QRMatrix::M_FINDER => false, // 6 - QRMatrix::M_SEPARATOR => false, // 8 - QRMatrix::M_ALIGNMENT => false, // 10 - QRMatrix::M_TIMING => false, // 12 - QRMatrix::M_FORMAT => false, // 14 - QRMatrix::M_VERSION => false, // 16 - QRMatrix::M_QUIETZONE => false, // 18 - QRMatrix::M_TEST => false, // 255 - // dark - QRMatrix::M_DARKMODULE << 8 => true, // 512 - QRMatrix::M_DATA << 8 => true, // 1024 - QRMatrix::M_FINDER << 8 => true, // 1536 - QRMatrix::M_ALIGNMENT << 8 => true, // 2560 - QRMatrix::M_TIMING << 8 => true, // 3072 - QRMatrix::M_FORMAT << 8 => true, // 3584 - QRMatrix::M_VERSION << 8 => true, // 4096 - QRMatrix::M_TEST << 8 => true, // 65280 - ]; + protected $moduleValues; /** * Sets the options, called internally by the constructor diff --git a/tests/Output/QRImageTest.php b/tests/Output/QRImageTest.php index 1ef0a9f48..f27be9df7 100644 --- a/tests/Output/QRImageTest.php +++ b/tests/Output/QRImageTest.php @@ -35,11 +35,7 @@ class QRImageTest extends QROutputTestAbstract{ $this->options->outputType = $type; $this->options->cachefile = $this::cachefile.$type; $this->setOutputInterface(); - $this->outputInterface->dump(); - - $this->options->cachefile = null; - $this->options->imageBase64 = false; - $this->setOutputInterface(); + $this->outputInterface->dump($this::cachefile.$type); $img = $this->outputInterface->dump(); if($type === QRCode::OUTPUT_IMAGE_JPG){ // jpeg encoding may cause different results