Explorar el Código

:octocat: better(?) module value handling

codemasher hace 7 años
padre
commit
3fd7e80148

+ 4 - 0
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 = '';

+ 36 - 65
src/Output/QRImage.php

@@ -12,42 +12,20 @@
 
 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
@@ -55,42 +33,50 @@ class QRImage extends QROutputAbstract{
 	protected $image;
 
 	/**
+	 * @see imagecolorallocate()
 	 * @var int
 	 */
-	protected $scale;
+	protected $background;
 
 	/**
-	 * @var int
+	 * @return void
 	 */
-	protected $length;
+	protected function setModuleValues():void{
 
-	/**
-	 * @see imagecolorallocate()
-	 * @var int
-	 */
-	protected $background;
+		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)
 		);
 	}
 

+ 24 - 9
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 .= '<div>';
 
-			foreach($row as $pixel){
-				$html .= '<span style="background: '.($this->options->moduleValues[$pixel] ?: 'lightgrey').';"></span>';
+			foreach($row as $M_TYPE){
+				$html .= '<span style="background: '.$this->moduleValues[$M_TYPE].';"></span>';
 			}
 
 			$html .= '</div>'.$this->options->eol;
@@ -59,13 +80,7 @@ class QRMarkup extends QROutputAbstract{
 		       .'<defs>'.$this->options->svgDefs.'</defs>'
 		       .$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){

+ 26 - 1
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()
 	 *

+ 24 - 0
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
 	 *

+ 23 - 11
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);

+ 3 - 0
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

+ 15 - 23
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

+ 1 - 5
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