mirror of
https://github.com/chillerlan/php-qrcode.git
synced 2026-09-01 13:08:14 +00:00
added QRMarkup & cleaned up the output
This commit is contained in:
+14
-83
@@ -20,37 +20,29 @@ 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;
|
||||
|
||||
if(!$this->options instanceof QRImageOptions){
|
||||
$this->options = new QRImageOptions;
|
||||
}
|
||||
|
||||
// clamp input (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));
|
||||
|
||||
foreach(['fgRed', 'fgGreen', 'fgBlue', 'bgRed', 'bgGreen', 'bgBlue'] as $val){
|
||||
$this->options->{$val} = max(0, min(255, (int)$this->options->{$val}));
|
||||
}
|
||||
|
||||
}
|
||||
protected $types = [
|
||||
QRCode::OUTPUT_IMAGE_GIF,
|
||||
QRCode::OUTPUT_IMAGE_JPG,
|
||||
QRCode::OUTPUT_IMAGE_PNG,
|
||||
];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function dump(){
|
||||
// svg doesn't need all this GD business
|
||||
if($this->options->type === QRCode::OUTPUT_IMAGE_SVG){
|
||||
return $this->toSVG();
|
||||
// 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));
|
||||
|
||||
foreach(['fgRed', 'fgGreen', 'fgBlue', 'bgRed', 'bgGreen', 'bgBlue'] as $val){
|
||||
$this->options->{$val} = max(0, min(255, (int)$this->options->{$val}));
|
||||
}
|
||||
|
||||
$length = $this->pixelCount * $this->options->pixelSize + $this->options->marginSize * 2;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 = '';
|
||||
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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%.
|
||||
|
||||
Reference in New Issue
Block a user