mirror of
https://github.com/chillerlan/php-qrcode.git
synced 2026-08-17 16:11:10 +00:00
📖
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
# `QROutputAbstract`
|
||||
|
||||
The abstract class `QROutputAbstract` contains several commonly used methods and properties and can be used as a basis for a custom output class.
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
### `$options` and `$matrix`
|
||||
|
||||
The `QROptions` and `QRMatrix` instances that were passed to the constructor of the output class.
|
||||
Both objects can be modified during runtime, for example to override settings or add matrix modifications.
|
||||
|
||||
|
||||
### `$moduleCount`, `$scale` and `$length`
|
||||
|
||||
These are convenience variables mostly to avoid multiple method calls to `QRMatrix::getSize()` and `QROptions::__get('scale')` inside loops,
|
||||
the `$length` is calculated from the aforementioned values (`$moduleCount * $scale`).
|
||||
The method `setMatrixDimensions()` can be called to update these 3 values after the matrix has been modified, e.g. by adding a quiet zone during output.
|
||||
|
||||
|
||||
### `$moduleValues`
|
||||
|
||||
The finalized map of `$M_TYPE` to value for the current output. This map is generated during invocation of the output class via `setModuleValues()`.
|
||||
|
||||
|
||||
### Copies of `QROptions` values
|
||||
|
||||
Some values from the `QROptions` instance are copied to properties to avoid calling the magic getters in long loops for a significant performance increase, e.g. in the module collector.
|
||||
Currently, the following values are copied via `copyVars()` during invocation:
|
||||
`$connectPaths`, `$excludeFromConnect`, `$eol`, `$drawLightModules`, `$drawCircularModules`, `$keepAsSquare`, `$circleRadius`.
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
### `setModuleValues()`
|
||||
|
||||
This method calls the abstract/interface methods `moduleValueIsValid()`, `prepareModuleValue()` and `getDefaultModuleValue()` to prepare the module values map.
|
||||
|
||||
|
||||
### `moduleValueIsValid()`
|
||||
|
||||
This method is declared in the `QROutputInterface` and needs to be implemented by the output class; it is `static` so that it can be called before invocation.
|
||||
The purpose is to determine whether the given `mixed` input is a valid module value for the current output class and returns `bool`.
|
||||
It's also useful to check values from `QROptions` such as `$bgColor` or `$transparencyColor`.
|
||||
|
||||
Below is a pseudo implementation, check the code of the several output classes for actual implementations
|
||||
(e.g. [`QRImagick::moduleValueIsValid()`](https://github.com/chillerlan/php-qrcode/blob/4bd4b59fdec72397f5b1f70da9cadcb76764191b/src/Output/QRImagick.php#L68-L96))
|
||||
|
||||
```php
|
||||
class MyOutput extends QROutputAbstract{
|
||||
|
||||
public static function moduleValueIsValid(mixed $value):bool{
|
||||
|
||||
// check the type of the input value first
|
||||
if(!is_expected_type($value)){
|
||||
return false;
|
||||
}
|
||||
|
||||
// do some more checks to determine the value
|
||||
if(!is_somehow_valid($value)){
|
||||
return false;
|
||||
}
|
||||
|
||||
// looks like we got a match
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### `prepareModuleValue()`
|
||||
|
||||
This method prepares the final replacement value from the given input.
|
||||
It might still be necessary to validate the given value despite it being checked earlier by `moduleValueIsValid()` -
|
||||
if nothing helps, this is a good place to throw an exception.
|
||||
Below a pseudo implementation example (see [`QRGdImage::prepareModuleValue()`](https://github.com/chillerlan/php-qrcode/blob/4bd4b59fdec72397f5b1f70da9cadcb76764191b/src/Output/QRGdImage.php#L138-L158)):
|
||||
|
||||
```php
|
||||
class MyOutput extends QROutputAbstract{
|
||||
|
||||
protected function prepareModuleValue(mixed $value):mixed{
|
||||
|
||||
// extended validation to make sure the values are valid for output
|
||||
// e.g. examine array values, clamp etc.
|
||||
if(!is_valid($value)){
|
||||
throw new QRCodeOutputException('invalid module value');
|
||||
}
|
||||
|
||||
return $this->modifyValue($value);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### `getDefaultModuleValue()`
|
||||
|
||||
Finally, setting a default value is required, in case a value for an `$M_TYPE` is not set or it's invalid.
|
||||
|
||||
```php
|
||||
class MyOutput extends QROutputAbstract{
|
||||
|
||||
protected function getDefaultModuleValue(bool $isDark):mixed{
|
||||
$defaultValue = ($isDark === true)
|
||||
? 'default value for dark'
|
||||
: 'default value for light';
|
||||
|
||||
return $this->prepareModuleValue($defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### `getModuleValue()` and `getModuleValueAt()`
|
||||
|
||||
Both methods return a module value, the main difference is that `getModuleValueAt()` is a convenience method
|
||||
that makes an extra call to retrieve the `$M_TYPE` from the given matrix coordinate to return the value via `getModuleValue()`.
|
||||
|
||||
A `foreach` loop over the matrix gives you the key (coordinate) *and* value of an array element:
|
||||
|
||||
```php
|
||||
class MyOutput extends QROutputAbstract{
|
||||
|
||||
public function dump(string $file = null):string{
|
||||
$lines = [];
|
||||
|
||||
foreach($this->matrix->getMatrix() as $y => $row){
|
||||
$lines[$y] = '';
|
||||
|
||||
foreach($row as $x => $M_TYPE){
|
||||
$lines[$y] .= $this->getModuleValue($M_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
return implode($this->options->eol, $lines);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
However, sometimes you might happen to use a `for` loop instead. The `for` loop leaves you only with the matrix coordinates, so you need to call `getModuleValueAt()`:
|
||||
|
||||
```php
|
||||
class MyOutput extends QROutputAbstract{
|
||||
|
||||
public function dump(string $file = null):string{
|
||||
$lines = [];
|
||||
|
||||
for($y = 0; $y < $this->moduleCount; $y++){
|
||||
$lines[$y] = '';
|
||||
|
||||
for($x = 0; $x < $this->moduleCount; $x++){
|
||||
$lines[$y] .= $this->getModuleValueAt($x, $y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return implode($this->options->eol, $lines);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### `setMatrixDimensions()`
|
||||
|
||||
As mentioned before, this method is supposed to set the values for the properties `$moduleCount`, `$scale` and `$length`.
|
||||
It is called in the constructor during invocation, but it might be necessary to call it again if the size of the matrix was changed in the output class
|
||||
(see [the round quiet zone example](https://github.com/chillerlan/php-qrcode/blob/99b1f9cf454ab1316cb643950a71caed3a6c0f5a/examples/svgRoundQuietzone.php#L38-L44) for a use case).
|
||||
|
||||
|
||||
### `getOutputDimensions()`
|
||||
|
||||
This method provides a simple way for consistent width/height values for the output (if applicable) which then can be changed by simply overriding this method.
|
||||
It returns a 2-element array that contains the values in a format that can be used by the output class, which is `QROutputAbstract::$length` (`$moduleCount * $scale`):
|
||||
|
||||
```php
|
||||
[$width, $height] = $this->getOutputDimensions();
|
||||
```
|
||||
|
||||
The output width and height can be changed in all places by simply overriding the method:
|
||||
|
||||
```php
|
||||
class MyOutput extends QROutputAbstract{
|
||||
|
||||
protected function getOutputDimensions():array{
|
||||
// adjust the height in order to add something under the QR Code
|
||||
return [$this->length, ($this->length + 69)];
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### `collectModules()`
|
||||
|
||||
The module collector is particularly useful for plain text based file formats, for example the various markup languages like SVG and HTML or other structured file formats such as EPS.
|
||||
This method takes a `Closure` as a parameter, which is called with 4 parameters: the module coordinates `$x` and `$y`, the `$M_TYPE` and `$M_TYPE_LAYER`.
|
||||
The `$M_TYPE_LAYER` is a copy of the `$M_TYPE` that represents the array key of the returned array and that may have been reassigned in the collector to another path layer, e.g. through `QROptions::$connectPaths`.
|
||||
|
||||
```php
|
||||
class MyOutput extends QROutputAbstract{
|
||||
|
||||
public function dump(string $file = null):string{
|
||||
|
||||
// collect the modules for the path elements
|
||||
$paths = $this->collectModules(fn(int $x, int $y, int $M_TYPE):string => sprintf('%d %d %012b', $x, $y, $M_TYPE));
|
||||
|
||||
// loop over the paths
|
||||
foreach($paths as $M_TYPE_LAYER => &$path){
|
||||
|
||||
if(empty($path)){
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = implode($this->options->eol, $path);
|
||||
}
|
||||
|
||||
return implode($this->options->eol, $paths);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Sometimes it can be necessary to override `collectModules()` in order to apply special effects such as random colors - you can find some implementations in [the SVG examples](https://github.com/chillerlan/php-qrcode/tree/main/examples).
|
||||
|
||||
|
||||
### `saveToFile()` and `toBase64DataURI()`
|
||||
|
||||
The void method `saveToFile()` takes a data blob and the `$file` given in `QROutputInterface::dump()` and save to the path if it is not `null` - the file path itself is not checked except for writability.
|
||||
|
||||
The final output can be transformed to a [base64 data URI](https://en.wikipedia.org/wiki/Data_URI_scheme) with `toBase64DataURI()`, where the data blob and a valid mime type as parameters - the mime type is not checked.
|
||||
|
||||
|
||||
|
||||
```php
|
||||
class MyOutput extends QROutputAbstract{
|
||||
|
||||
public function dump(string $file = null):string{
|
||||
$output = 'qrcode data string';
|
||||
|
||||
// save the plain data to file
|
||||
$this->saveToFile($output, $file);
|
||||
|
||||
// base64 encoding may be called optionally
|
||||
if($this->options->outputBase64){
|
||||
$output = $this->toBase64DataURI($output, 'text/plain');
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user