Pārlūkot izejas kodu

added QRMarkup & cleaned up the output

smiley 9 gadi atpakaļ
vecāks
revīzija
03d5d92fbe

+ 13 - 82
src/Output/QRImage.php

@@ -20,21 +20,24 @@ use chillerlan\QRCode\QRCode;
 class QRImage extends QROutputAbstract{
 
 	/**
-	 * @var \chillerlan\QRCode\Output\QRImageOptions $outputOptions
+	 * @var string
 	 */
-	protected $options;
+	protected $optionsInterface = QRImageOptions::class;
 
 	/**
-	 * @var \chillerlan\QRCode\Output\QRImageOptions $outputOptions
+	 * @var array
 	 */
-	public function __construct(QRImageOptions $outputOptions = null){
-		$this->options = $outputOptions;
+	protected $types = [
+		QRCode::OUTPUT_IMAGE_GIF,
+		QRCode::OUTPUT_IMAGE_JPG,
+		QRCode::OUTPUT_IMAGE_PNG,
+	];
 
-		if(!$this->options instanceof QRImageOptions){
-			$this->options = new QRImageOptions;
-		}
-
-		// clamp input (determine sane values!)
+	/**
+	 * @return string
+	 */
+	public function dump(){
+		// clamp input (@todo: determine sane values!)
 		$this->options->pixelSize = max(1, min(25, (int)$this->options->pixelSize));
 		$this->options->marginSize = max(0, min(25, (int)$this->options->marginSize));
 
@@ -42,17 +45,6 @@ class QRImage extends QROutputAbstract{
 			$this->options->{$val} = max(0, min(255, (int)$this->options->{$val}));
 		}
 
-	}
-
-	/**
-	 * @return string
-	 */
-	public function dump(){
-		// svg doesn't need all this GD business
-		if($this->options->type === QRCode::OUTPUT_IMAGE_SVG){
-			return $this->toSVG();
-		}
-
 		$length     = $this->pixelCount * $this->options->pixelSize + $this->options->marginSize * 2;
 		$image      = imagecreatetruecolor($length, $length);
 		$foreground = imagecolorallocate($image, $this->options->fgRed, $this->options->fgGreen, $this->options->fgBlue);
@@ -117,65 +109,4 @@ class QRImage extends QROutputAbstract{
 		return $imageData;
 	}
 
-	/**
-	 * @return string
-	 */
-	protected function toSVG(){
-		$length     = $this->pixelCount * $this->options->pixelSize + $this->options->marginSize * 2;
-		$class      = 'f' . hash('crc32', microtime(true));
-		$foreground = 'rgb(' . $this->options->fgRed . ',' . $this->options->fgGreen . ',' . $this->options->fgBlue . ')';
-		$background = (bool)$this->options->transparent
-			? 'transparent'
-			: 'rgb(' . $this->options->bgRed . ',' . $this->options->bgGreen . ',' . $this->options->bgBlue . ')';
-
-		ob_start();
-
-		// svg header
-		echo '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="' . $length . '" height="' . $length . '" viewBox="0 0 ' . $length . ' ' . $length . '" style="background-color:' . $background . '"><defs><style>.' . $class . '{fill:' . $foreground . '} rect{shape-rendering:crispEdges}</style></defs>';
-
-		// svg body
-		foreach($this->matrix AS $r=>$row){
-			//we'll combine active blocks within a single row as a lightweight compression technique
-			$from = -1;
-			$count = 0;
-
-			foreach($row AS $c=>$pixel){
-				if($pixel){
-					$count++;
-					if($from < 0)
-						$from = $c;
-				}
-				else if($from >= 0){
-					echo '<rect x="' . ($from * $this->options->pixelSize + $this->options->marginSize) . '" y="' . ($r * $this->options->pixelSize + $this->options->marginSize) . '" width="' . ($this->options->pixelSize * $count) . '" height="' . $this->options->pixelSize . '" class="' . $class . '" />';
-
-					// reset count
-					$from = -1;
-					$count = 0;
-				}
-			}
-
-			// close off the row, if applicable
-			if($from >= 0){
-				echo '<rect x="' . ($from * $this->options->pixelSize + $this->options->marginSize) . '" y="' . ($r * $this->options->pixelSize + $this->options->marginSize) . '" width="' . ($this->options->pixelSize * $count) . '" height="' . $this->options->pixelSize . '" class="' . $class . '" />';
-			}
-		}
-
-		// close svg
-		echo '</svg>';
-		$imageData = ob_get_clean();
-
-		// if saving to file, append the correct headers
-		if($this->options->cachefile){
-			if(false === @file_put_contents($this->options->cachefile, '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' . "\n" . $imageData)){
-				throw new QRCodeOutputException('Could not write to cache file.');
-			}
-		}
-
-		if((bool)$this->options->base64){
-			$imageData = 'data:image/svg+xml;base64,'.base64_encode($imageData);
-		}
-
-		return $imageData;
-	}
-
 }

+ 4 - 4
src/Output/QRImageOptions.php

@@ -1,5 +1,6 @@
 <?php
 /**
+ * Class QRImageOptions
  *
  * @filesource   QRImageOptions.php
  * @created      08.12.2015
@@ -10,19 +11,18 @@
  */
 
 namespace chillerlan\QRCode\Output;
+
 use chillerlan\QRCode\QRCode;
 
 /**
- * Class QRImageOptions
+ *
  */
-class QRImageOptions{
+class QRImageOptions extends QROutputOptionsAbstract{
 
 	public $type = QRCode::OUTPUT_IMAGE_PNG;
 
 	public $base64 = true;
 
-	public $cachefile = null;
-
 	public $pixelSize = 5;
 	public $marginSize = 5;
 

+ 133 - 0
src/Output/QRMarkup.php

@@ -0,0 +1,133 @@
+<?php
+/**
+ * Class QRMarkup
+ *
+ * @filesource   QRMarkup.php
+ * @created      17.12.2016
+ * @package      chillerlan\QRCode\Output
+ * @author       Smiley <smiley@chillerlan.net>
+ * @copyright    2016 Smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\QRCode;
+
+/**
+ *
+ */
+class QRMarkup extends QROutputAbstract{
+
+	/**
+	 * @var string
+	 */
+	protected $optionsInterface = QRMarkupOptions::class;
+
+	/**
+	 * @var array
+	 */
+	protected $types = [
+		QRCode::OUTPUT_MARKUP_HTML,
+		QRCode::OUTPUT_MARKUP_SVG,
+	];
+
+	/**
+	 * @return string
+	 */
+	public function dump(){
+		switch($this->options->type){
+			case QRCode::OUTPUT_MARKUP_SVG : return $this->toSVG();
+			case QRCode::OUTPUT_MARKUP_HTML:
+			default:
+				return $this->toHTML();
+		}
+	}
+
+	/**
+	 * @return string
+	 */
+	protected function toHTML(){
+		$html = '';
+
+		foreach($this->matrix as $row){
+			// in order to not bloat the output too much, we use the shortest possible valid HTML tags
+			$html .= '<'.$this->options->htmlRowTag.'>';
+
+			foreach($row as $col){
+				$tag = $col
+					? 'b'  // dark
+					: 'i'; // light
+
+				$html .= '<'.$tag.'></'.$tag.'>';
+			}
+
+			if(!(bool)$this->options->htmlOmitEndTag){
+				$html .= '</'.$this->options->htmlRowTag.'>';
+			}
+
+			$html .= $this->options->eol;
+		}
+
+		return $html;
+	}
+
+	/**
+	 * @return string
+	 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
+	 */
+	protected function toSVG(){
+		$length = $this->pixelCount * $this->options->pixelSize + $this->options->marginSize * 2;
+		$class  = !empty($this->options->cssClass) ? $this->options->cssClass : hash('crc32', microtime(true));
+
+		// svg header
+		$svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="'.$length.'" height="'.$length.'" viewBox="0 0 '.$length.' '.$length.'" style="background-color:'.$this->options->bgColor.'">'.$this->options->eol.
+		       '<defs><style>.'.$class.'{fill:'.$this->options->fgColor.'} rect{shape-rendering:crispEdges}</style></defs>'.$this->options->eol;
+
+		// svg body
+		foreach($this->matrix as $r => $row){
+			//we'll combine active blocks within a single row as a lightweight compression technique
+			$from  = -1;
+			$count = 0;
+
+			foreach($row as $c => $pixel){
+				if($pixel){
+					$count++;
+
+					if($from < 0){
+						$from = $c;
+					}
+				}
+				elseif($from >= 0){
+					$svg .= '<rect x="'.($from * $this->options->pixelSize + $this->options->marginSize).'" y="'.($r * $this->options->pixelSize + $this->options->marginSize)
+					        .'" width="'.($this->options->pixelSize * $count).'" height="'.$this->options->pixelSize.'" class="'.$class.'" />'.$this->options->eol;
+
+					// reset count
+					$from  = -1;
+					$count = 0;
+				}
+			}
+
+			// close off the row, if applicable
+			if($from >= 0){
+				$svg .= '<rect x="'.($from * $this->options->pixelSize + $this->options->marginSize).'" y="'.($r * $this->options->pixelSize + $this->options->marginSize)
+				        .'" width="'.($this->options->pixelSize * $count).'" height="'.$this->options->pixelSize.'" class="'.$class.'" />'.$this->options->eol;
+			}
+		}
+
+		// close svg
+		$svg .= '</svg>'.$this->options->eol;
+
+		// if saving to file, append the correct headers
+		if($this->options->cachefile){
+			$svg = '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'.$this->options->eol.$svg;
+
+			if(@file_put_contents($this->options->cachefile, $svg) === false){
+				throw new QRCodeOutputException('Could not write to cache file.'); // @codeCoverageIgnore
+			}
+		}
+
+		return $svg;
+	}
+
+}

+ 38 - 0
src/Output/QRMarkupOptions.php

@@ -0,0 +1,38 @@
+<?php
+/**
+ * Class QRMarkupOptions
+ *
+ * @filesource   QRMarkupOptions.php
+ * @created      08.12.2015
+ * @package      chillerlan\QRCode\Output
+ * @author       Smiley <smiley@chillerlan.net>
+ * @copyright    2015 Smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\QRCode;
+
+/**
+ *
+ */
+class QRMarkupOptions extends QROutputOptionsAbstract{
+
+	public $type = QRCode::OUTPUT_MARKUP_SVG;
+
+	public $htmlRowTag = 'p';
+
+	public $htmlOmitEndTag = true;
+
+	public $fgColor = '#000';
+
+	public $bgColor = '#fff';
+
+	public $pixelSize = 5;
+
+	public $marginSize = 5;
+
+	public $cssClass = '';
+
+}

+ 27 - 0
src/Output/QROutputAbstract.php

@@ -17,6 +17,16 @@ namespace chillerlan\QRCode\Output;
  */
 abstract class QROutputAbstract implements QROutputInterface{
 
+	/**
+	 * @var string
+	 */
+	protected $optionsInterface;
+
+	/**
+	 * @var array
+	 */
+	protected $types;
+
 	/**
 	 * @var array
 	 */
@@ -32,6 +42,23 @@ abstract class QROutputAbstract implements QROutputInterface{
 	 */
 	protected $options;
 
+	/**
+	 * @var \chillerlan\QRCode\Output\QROutputOptionsAbstract $outputOptions
+	 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
+	 */
+	public function __construct(QROutputOptionsAbstract $outputOptions = null){
+		$this->options = $outputOptions;
+
+		if($this->optionsInterface && !$this->options instanceof $this->optionsInterface){
+			$this->options = new $this->optionsInterface;
+		}
+
+		if(is_array($this->types) && !in_array($this->options->type, $this->types , true)){
+			throw new QRCodeOutputException('Invalid output type!');
+		}
+
+	}
+
 	/**
 	 * @param array $matrix
 	 *

+ 26 - 0
src/Output/QROutputOptionsAbstract.php

@@ -0,0 +1,26 @@
+<?php
+/**
+ * Class QROutputOptionsAbstract
+ *
+ * @filesource   QROutputOptionsAbstract.php
+ * @created      17.12.2016
+ * @package      chillerlan\QRCode\Output
+ * @author       Smiley <smiley@chillerlan.net>
+ * @copyright    2016 Smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+/**
+ *
+ */
+abstract class QROutputOptionsAbstract{
+
+	public $type;
+
+	public $eol = PHP_EOL;
+
+	public $cachefile = null;
+
+}

+ 7 - 51
src/Output/QRString.php

@@ -19,27 +19,12 @@ use chillerlan\QRCode\QRCode;
  */
 class QRString extends QROutputAbstract{
 
-	/**
-	 * @var \chillerlan\QRCode\Output\QRStringOptions
-	 */
-	protected $options;
+	protected $optionsInterface = QRStringOptions::class;
 
-	/**
-	 * @var \chillerlan\QRCode\Output\QRStringOptions $outputOptions
-	 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
-	 */
-	public function __construct(QRStringOptions $outputOptions = null){
-		$this->options = $outputOptions;
-
-		if(!$this->options instanceof QRStringOptions){
-			$this->options = new QRStringOptions;
-		}
-
-		if(!in_array($this->options->type, [QRCode::OUTPUT_STRING_TEXT, QRCode::OUTPUT_STRING_JSON, QRCode::OUTPUT_STRING_HTML], true)){
-			throw new QRCodeOutputException('Invalid string output type!');
-		}
-
-	}
+	protected $types = [
+		QRCode::OUTPUT_STRING_TEXT,
+		QRCode::OUTPUT_STRING_JSON,
+	];
 
 	/**
 	 * @return string
@@ -47,11 +32,10 @@ class QRString extends QROutputAbstract{
 	public function dump(){
 
 		switch($this->options->type){
-			case QRCode::OUTPUT_STRING_JSON: return json_encode($this->matrix);
 			case QRCode::OUTPUT_STRING_TEXT: return $this->toString();
-			case QRCode::OUTPUT_STRING_HTML:
+			case QRCode::OUTPUT_STRING_JSON:
 			default:
-				return $this->toHTML();
+				return json_encode($this->matrix);
 		}
 
 	}
@@ -75,32 +59,4 @@ class QRString extends QROutputAbstract{
 		return $str;
 	}
 
-	/**
-	 * @return string
-	 */
-	protected function toHTML(){
-		$html = '';
-
-		foreach($this->matrix as $row){
-			// in order to not bloat the output too much, we use the shortest possible valid HTML tags
-			$html .= '<'.$this->options->htmlRowTag.'>';
-
-			foreach($row as $col){
-				$tag = $col
-					? 'b'  // dark
-					: 'i'; // light
-
-				$html .= '<'.$tag.'></'.$tag.'>';
-			}
-
-			if(!(bool)$this->options->htmlOmitEndTag){
-				$html .= '</'.$this->options->htmlRowTag.'>';
-			}
-
-			$html .= $this->options->eol;
-		}
-
-		return $html;
-	}
-
 }

+ 3 - 8
src/Output/QRStringOptions.php

@@ -11,23 +11,18 @@
  */
 
 namespace chillerlan\QRCode\Output;
+
 use chillerlan\QRCode\QRCode;
 
 /**
  *
  */
-class QRStringOptions{
+class QRStringOptions extends QROutputOptionsAbstract{
 
-	public $type = QRCode::OUTPUT_STRING_HTML;
+	public $type = QRCode::OUTPUT_STRING_JSON;
 
 	public $textDark = '#';
 
 	public $textLight = ' ';
 
-	public $eol = PHP_EOL;
-
-	public $htmlRowTag = 'p';
-
-	public $htmlOmitEndTag = true;
-
 }

+ 6 - 4
src/QRCode.php

@@ -27,14 +27,16 @@ class QRCode{
 	/**
 	 * API constants
 	 */
-	const OUTPUT_STRING_TEXT = 0;
-	const OUTPUT_STRING_JSON = 1;
-	const OUTPUT_STRING_HTML = 2;
+	const OUTPUT_STRING_TEXT = 'txt';
+	const OUTPUT_STRING_JSON = 'json';
+
+	const OUTPUT_MARKUP_HTML = 'html';
+	const OUTPUT_MARKUP_SVG  = 'svg';
+#	const OUTPUT_MARKUP_XML  = 'xml'; // anyone?
 
 	const OUTPUT_IMAGE_PNG = 'png';
 	const OUTPUT_IMAGE_JPG = 'jpg';
 	const OUTPUT_IMAGE_GIF = 'gif';
-	const OUTPUT_IMAGE_SVG = 'svg';
 
 	const ERROR_CORRECT_LEVEL_L = 1; // 7%.
 	const ERROR_CORRECT_LEVEL_M = 0; // 15%.