aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php')
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php230
1 files changed, 181 insertions, 49 deletions
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php b/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php
index d4ed3d0c9..a2757ac8c 100644
--- a/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php
+++ b/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php
@@ -2,9 +2,7 @@
/**
* Class QROutputAbstract
*
- * @filesource QROutputAbstract.php
* @created 09.12.2015
- * @package chillerlan\QRCode\Output
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
@@ -12,10 +10,10 @@
namespace chillerlan\QRCode\Output;
-use chillerlan\QRCode\{Data\QRMatrix, QRCode};
+use chillerlan\QRCode\Data\QRMatrix;
use chillerlan\Settings\SettingsContainerInterface;
-
-use function call_user_func_array, dirname, file_put_contents, get_called_class, in_array, is_writable, sprintf;
+use Closure;
+use function base64_encode, dirname, file_put_contents, is_writable, ksort, sprintf;
/**
* common output abstract
@@ -25,30 +23,11 @@ abstract class QROutputAbstract implements QROutputInterface{
/**
* the current size of the QR matrix
*
- * @see \chillerlan\QRCode\Data\QRMatrix::size()
+ * @see \chillerlan\QRCode\Data\QRMatrix::getSize()
*/
protected int $moduleCount;
/**
- * the current output mode
- *
- * @see \chillerlan\QRCode\QROptions::$outputType
- */
- protected string $outputMode;
-
- /**
- * the default output mode of the current output module
- */
- protected string $defaultMode;
-
- /**
- * the current scaling for a QR pixel
- *
- * @see \chillerlan\QRCode\QROptions::$scale
- */
- protected int $scale;
-
- /**
* the side length of the QR image (modules * scale)
*/
protected int $length;
@@ -68,62 +47,215 @@ abstract class QROutputAbstract implements QROutputInterface{
*/
protected SettingsContainerInterface $options;
+ /** @see \chillerlan\QRCode\QROptions::$scale */
+ protected int $scale;
+ /** @see \chillerlan\QRCode\QROptions::$connectPaths */
+ protected bool $connectPaths;
+ /** @see \chillerlan\QRCode\QROptions::$excludeFromConnect */
+ protected array $excludeFromConnect;
+ /** @see \chillerlan\QRCode\QROptions::$eol */
+ protected string $eol;
+ /** @see \chillerlan\QRCode\QROptions::$drawLightModules */
+ protected bool $drawLightModules;
+ /** @see \chillerlan\QRCode\QROptions::$drawCircularModules */
+ protected bool $drawCircularModules;
+ /** @see \chillerlan\QRCode\QROptions::$keepAsSquare */
+ protected array $keepAsSquare;
+ /** @see \chillerlan\QRCode\QROptions::$circleRadius */
+ protected float $circleRadius;
+ protected float $circleDiameter;
+
/**
* QROutputAbstract constructor.
*/
public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){
- $this->options = $options;
- $this->matrix = $matrix;
- $this->moduleCount = $this->matrix->size();
+ $this->options = $options;
+ $this->matrix = $matrix;
+
+ if($this->options->invertMatrix){
+ $this->matrix->invert();
+ }
+
+ $this->copyVars();
+ $this->setMatrixDimensions();
+ $this->setModuleValues();
+ }
+
+ /**
+ * Creates copies of several QROptions values to avoid calling the magic getters
+ * in long loops for a significant performance increase.
+ *
+ * These variables are usually used in the "module" methods and are called up to 31329 times (at version 40).
+ */
+ protected function copyVars():void{
+
+ $vars = [
+ 'connectPaths',
+ 'excludeFromConnect',
+ 'eol',
+ 'drawLightModules',
+ 'drawCircularModules',
+ 'keepAsSquare',
+ 'circleRadius',
+ ];
+
+ foreach($vars as $property){
+ $this->{$property} = $this->options->{$property};
+ }
+
+ $this->circleDiameter = ($this->circleRadius * 2);
+ }
+
+ /**
+ * Sets/updates the matrix dimensions
+ *
+ * Call this method if you modify the matrix from within your custom module in case the dimensions have been changed
+ */
+ protected function setMatrixDimensions():void{
+ $this->moduleCount = $this->matrix->getSize();
$this->scale = $this->options->scale;
- $this->length = $this->moduleCount * $this->scale;
+ $this->length = ($this->moduleCount * $this->scale);
+ }
+
+ /**
+ * Returns a 2 element array with the current output width and height
+ *
+ * The type and units of the values depend on the output class. The default value is the current module count * scale.
+ */
+ protected function getOutputDimensions():array{
+ return [$this->length, $this->length];
+ }
- $class = get_called_class();
+ /**
+ * Sets the initial module values
+ */
+ protected function setModuleValues():void{
- if(isset(QRCode::OUTPUT_MODES[$class]) && in_array($this->options->outputType, QRCode::OUTPUT_MODES[$class])){
- $this->outputMode = $this->options->outputType;
+ // first fill the map with the default values
+ foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){
+ $this->moduleValues[$M_TYPE] = $this->getDefaultModuleValue($defaultValue);
}
- $this->setModuleValues();
+ // now loop over the options values to replace defaults and add extra values
+ foreach($this->options->moduleValues as $M_TYPE => $value){
+ if($this::moduleValueIsValid($value)){
+ $this->moduleValues[$M_TYPE] = $this->prepareModuleValue($value);
+ }
+ }
+
+ }
+
+ /**
+ * Prepares the value for the given input (return value depends on the output class)
+ *
+ * @param mixed $value
+ *
+ * @return mixed|null
+ */
+ abstract protected function prepareModuleValue($value);
+
+ /**
+ * Returns a default value for either dark or light modules (return value depends on the output class)
+ *
+ * @return mixed|null
+ */
+ abstract protected function getDefaultModuleValue(bool $isDark);
+
+ /**
+ * Returns the prepared value for the given $M_TYPE
+ *
+ * @return mixed return value depends on the output class
+ * @throws \chillerlan\QRCode\Output\QRCodeOutputException if $moduleValues[$M_TYPE] doesn't exist
+ */
+ protected function getModuleValue(int $M_TYPE){
+
+ if(!isset($this->moduleValues[$M_TYPE])){
+ throw new QRCodeOutputException(sprintf('$M_TYPE %012b not found in module values map', $M_TYPE));
+ }
+
+ return $this->moduleValues[$M_TYPE];
+ }
+
+ /**
+ * Returns the prepared module value at the given coordinate [$x, $y] (convenience)
+ *
+ * @return mixed|null
+ */
+ protected function getModuleValueAt(int $x, int $y){
+ return $this->getModuleValue($this->matrix->get($x, $y));
}
/**
- * Sets the initial module values (clean-up & defaults)
+ * Returns a base64 data URI for the given string and mime type
*/
- abstract protected function setModuleValues():void;
+ protected function toBase64DataURI(string $data, ?string $mime = null):string{
+ return sprintf('data:%s;base64,%s', ($mime ?? $this::MIME_TYPE), base64_encode($data));
+ }
/**
- * saves the qr data to a file
+ * Saves the qr $data to a $file. If $file is null, nothing happens.
*
* @see file_put_contents()
- * @see \chillerlan\QRCode\QROptions::cachefile
+ * @see \chillerlan\QRCode\QROptions::$cachefile
*
* @throws \chillerlan\QRCode\Output\QRCodeOutputException
*/
- protected function saveToFile(string $data, string $file):bool{
+ protected function saveToFile(string $data, ?string $file = null):void{
+
+ if($file === null){
+ return;
+ }
if(!is_writable(dirname($file))){
- throw new QRCodeOutputException(sprintf('Could not write data to cache file: %s', $file));
+ throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s', $file));
}
- return (bool)file_put_contents($file, $data);
+ if(file_put_contents($file, $data) === false){
+ throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s (file_put_contents error)', $file));
+ }
}
/**
- * @inheritDoc
+ * collects the modules per QRMatrix::M_* type and runs a $transform function on each module and
+ * returns an array with the transformed modules
+ *
+ * The transform callback is called with the following parameters:
+ *
+ * $x - current column
+ * $y - current row
+ * $M_TYPE - field value
+ * $M_TYPE_LAYER - (possibly modified) field value that acts as layer id
*/
- public function dump(string $file = null){
- $file ??= $this->options->cachefile;
+ protected function collectModules(Closure $transform):array{
+ $paths = [];
- // call the built-in output method with the optional file path as parameter
- // to make the called method aware if a cache file was given
- $data = call_user_func_array([$this, $this->outputMode ?? $this->defaultMode], [$file]);
+ // collect the modules for each type
+ foreach($this->matrix->getMatrix() as $y => $row){
+ foreach($row as $x => $M_TYPE){
+ $M_TYPE_LAYER = $M_TYPE;
- if($file !== null){
- $this->saveToFile($data, $file);
+ if($this->connectPaths && !$this->matrix->checkTypeIn($x, $y, $this->excludeFromConnect)){
+ // to connect paths we'll redeclare the $M_TYPE_LAYER to data only
+ $M_TYPE_LAYER = QRMatrix::M_DATA;
+
+ if($this->matrix->isDark($M_TYPE)){
+ $M_TYPE_LAYER = QRMatrix::M_DATA_DARK;
+ }
+ }
+
+ // collect the modules per $M_TYPE
+ $module = $transform($x, $y, $M_TYPE, $M_TYPE_LAYER);
+
+ if(!empty($module)){
+ $paths[$M_TYPE_LAYER][] = $module;
+ }
+ }
}
- return $data;
+ // beautify output
+ ksort($paths);
+
+ return $paths;
}
}