Skip to content

Commit

Permalink
📖
Browse files Browse the repository at this point in the history
  • Loading branch information
codemasher committed Oct 4, 2023
1 parent 97ee549 commit 171f0d9
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 4 deletions.
221 changes: 221 additions & 0 deletions docs/Customizing/Module-Values.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# Module values

## Basics

The QR Code matrix is a 2-dimensional array of numerical values that hold a bit mask for
each QR pixel ("module" as per specification), the so-called "module type" or `$M_TYPE`, which is represented by
[the `QRMatrix::M_*` constants](https://chillerlan.github.io/php-qrcode/classes/chillerlan-QRCode-Data-QRMatrix.html#toc-constants).
You can assign different values for the several [function patterns](../Appendix/Terminology.md#function-patterns) to colorize them or even draw pixel-art.


## Assigning values

To map the values and properly render the modules for the given `QROutputInterface`, it may be necessary to overwrite the
[default values](https://chillerlan.github.io/php-qrcode/classes/chillerlan-QRCode-Output-QROutputInterface.html#constant_DEFAULT_MODULE_VALUES),
that are replaced by the user defined values in `QROptions::$moduleValues` during the render process.

The map of `QRMatrix::M_*` constants => default values looks similar to the following:

```php
$options->moduleValues = [
// light
QRMatrix::M_NULL => false,
QRMatrix::M_DARKMODULE_LIGHT => false,
QRMatrix::M_DATA => false,
QRMatrix::M_FINDER => false,
QRMatrix::M_SEPARATOR => false,
QRMatrix::M_ALIGNMENT => false,
QRMatrix::M_TIMING => false,
QRMatrix::M_FORMAT => false,
QRMatrix::M_VERSION => false,
QRMatrix::M_QUIETZONE => false,
QRMatrix::M_LOGO => false,
QRMatrix::M_FINDER_DOT_LIGHT => false,
QRMatrix::M_TEST => false,
// dark
QRMatrix::M_DARKMODULE => true,
QRMatrix::M_DATA_DARK => true,
QRMatrix::M_FINDER_DARK => true,
QRMatrix::M_SEPARATOR_DARK => true,
QRMatrix::M_ALIGNMENT_DARK => true,
QRMatrix::M_TIMING_DARK => true,
QRMatrix::M_FORMAT_DARK => true,
QRMatrix::M_VERSION_DARK => true,
QRMatrix::M_QUIETZONE_DARK => true,
QRMatrix::M_LOGO_DARK => true,
QRMatrix::M_FINDER_DOT => true,
QRMatrix::M_TEST_DARK => true,
];
```

Not all the module values need to be specified - missing values will be filled with the internal default values
for `true` (dark) and `false` (light) respectively. The `QROutputInterface` inheritors implement a `moduleValueIsValid()`
method that checks if the given value is valid for that particular class:

```php
// set an initial value that acts as default
$dark = 'rgba(0, 0, 0, 0.5)';

// try to receive user input
if(QRMarkupSVG::moduleValueIsValid($_GET['qr_dark'])){
// module values for HTML, SVG and other markup may need special treatment,
// e.g. only accept hexadecimal values from user input
// as moduleValueIsValid() just checks for the general syntax
$dark = sanitize_user_input($_GET['qr_dark']);
}

$options->moduleValues = [
QRMatrix::M_DATA_DARK => $dark,
QRMatrix::M_FINDER_DARK => $dark,
QRMatrix::M_ALIGNMENT_DARK => $dark,
QRMatrix::M_FINDER_DOT => $dark,
];
```

The several output classes may need different substitute values (you can find examples [in the test `moduleValueProvider()` for each output class](https://github.com/chillerlan/php-qrcode/tree/main/tests/Output)):

```php
// for HTML, SVG and ImageMagick
$options->moduleValues = [
QRMatrix::M_DATA => '#ffffff',
QRMatrix::M_DATA_DARK => '#000000',
// ...
];

// for the GdImage, EPS and FPDF output types
$options->moduleValues = [
QRMatrix::M_DATA => [255, 255, 255],
QRMatrix::M_DATA_DARK => [0, 0, 0],
// ...
];

// for string/text output
$options->moduleValues = [
QRMatrix::M_DATA => '░░',
QRMatrix::M_DATA_DARK => '██',
// ...
];
```


## Handling in your own `QROutputInterface`

### Setting module values

[`QROutputAbstract::setModuleValues()`](https://chillerlan.github.io/php-qrcode/classes/chillerlan-QRCode-Output-QROutputAbstract.html#method_setModuleValues)
calls the 3 abstract methods `moduleValueIsValid()`, `getModuleValue()` and `getDefaultModuleValue()` to fill the internal
module value map with the values given via `QROptions::$moduleValues`:

```php
protected function setModuleValues():void{

foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){
$value = ($this->options->moduleValues[$M_TYPE] ?? null);

$this->moduleValues[$M_TYPE] = $this->moduleValueIsValid($value)
? $this->getModuleValue($value)
: $this->getDefaultModuleValue($defaultValue);
}

}
```

In the following example we'll create these methods for the `GdImage` output.
Since [`imagecolorallocate()`](https://www.php.net/manual/function.imagecolorallocate) and other GD functions accept 3 values
for RGB color (or 4 in case of RGBA), we'll supply these as a array where each value is an integer between 0 and 255 (`[RRR, GGG, BBB, (, AAA)]`).

First we need to validate the input:

```php
protected function moduleValueIsValid($value):bool{

// nowhere near valid
if(!is_array($value) || count($value) !== 3){
return false;
}

// now iterate over the values
foreach($value as $color){

// non-integers won't work
if(!is_int($color)){
return false;
}

// a strict check - we could also just ignore outliers and clamp the values instead
if($color < 0 || $color > 255){
return false;
}
}

return true; // yay!
}
```

Now we can prepare the value:

```php
protected function getModuleValue($value):array{
// we call array_values() so we don't run into string-key related issues
return array_map(fn(int $val):int => max(0, min(255, $val)), array_values($value));
}
```

And finally we need to provide default values:

```php
protected function getDefaultModuleValue(bool $isDark):array{
return $isDark ? [0, 0, 0] : [255, 255, 255];
}
```

Now that everything is ready and set, we can use the values in our GD functions:

```php
$color = imagecolorallocate($this->image, ...$this->moduleValues[$M_TYPE]);
```


### Using the module values

The state of the `$M_TYPE` is set with the `QRMatrix::IS_DARK` constant:

```php
// set to dark (true) with bitwise OR:
$M_TYPE = ($M_TYPE | QRMatrix::IS_DARK);

// set to light (false) with bitwise AND NOT
$M_TYPE = ($M_TYPE & ~QRMatrix::IS_DARK);

// toggle the opposite state with bitwise XOR
$M_TYPE = ($M_TYPE ^ QRMatrix::IS_DARK);
```

You can manually check whether the module is dark:

```php
($value & QRMatrix::IS_DARK) === QRMatrix::IS_DARK;
```

However it is much more convenient to use the `QRMatrix` methods for that:

```php
for($y = 0; $y < $this->moduleCount; $y++){ // rows
for($x = 0; $x < $this->moduleCount; $x++){ // columns
// sets current module as dark (true) with the M_DATA type
$this->matrix->set($x, $y, true, QRMatrix::M_DATA);

// -> true (shortcut for checkType($x, $y, QRMatrix::IS_DARK))
$this->matrix->check($x, $y);

// -> true (current module is of type M_DATA)
$this->matrix->checkType($x, $y, QRMatrix::M_DATA);

// -> true (current module is of type IS_DARK)
$this->matrix->checkType($x, $y, QRMatrix::IS_DARK);

// -> false, type is M_DATA
$this->matrix->checkTypeIn($x, $y, [QRMatrix::M_FINDER_DARK, QRMatrix::M_ALIGNMENT]);
}
}
```
5 changes: 5 additions & 0 deletions docs/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ The markdown sources for the [Read the Docs online manual](https://php-qrcode.re
- [Configuration settings](./Usage/Configuration-settings.md)


### Customizing output

- [Module values](./Customizing/Module-Values.md)


### Built-In Output Modules

- [QREps](./Built-In-Output/QREps.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/Usage/Advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Configuration via `QROptions`

The [`QROptions`](https://github.com/chillerlan/php-qrcode/blob/main/src/QROptions.php) class is a container based on [chillerlan/php-settings-container](https://github.com/chillerlan/php-settings-container) that behaves similar to a [`\stdClass`](https://www.php.net/manual/class.stdclass) object, but with fixed properties.
A list with all available `QROptions` can be found under [cnfiguration settings](../Usage/Configuration-settings.md).
A list with all available `QROptions` can be found under [configuration settings](../Usage/Configuration-settings.md).

```php
$options = new QROptions;
Expand Down
7 changes: 6 additions & 1 deletion docs/Usage/Configuration-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,11 @@ Sets the value for the "preserveAspectRatio" on the `<svg>` element

String substitute for dark

**See also:**

- [en.wikipedia.org/wiki/Block_Elements](https://en.wikipedia.org/wiki/Block_Elements)
- [en.wikipedia.org/wiki/ANSI_escape_code#8-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit)


## textLight

Expand All @@ -407,7 +412,7 @@ Whether to return matrix values in JSON as booleans or `$M_TYPE` integers

## fpdfMeasureUnit

Measurement unit for `FPDF` output: pt, mm, cm, in (defaults to "pt")
Measurement unit for `FPDF` output: `pt`, `mm`, `cm`, `in` (default: `pt`)

**See also:**

Expand Down
2 changes: 1 addition & 1 deletion docs/Usage/Overview.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Overview

A PHP QR Code generator based on the [implementation by Kazuhiko Arase](https://github.com/kazuhikoarase/qrcode-generator), namespaced, cleaned up, improved and other stuff. <br>
A PHP QR Code generator based on the [implementation by Kazuhiko Arase](https://github.com/kazuhikoarase/qrcode-generator), namespaced, cleaned up, improved and other stuff.
It also features a QR Code reader based on a [PHP port](https://github.com/khanamiryan/php-qrcode-detector-decoder) of the [ZXing library](https://github.com/zxing/zxing).


Expand Down
6 changes: 6 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ This work is licensed under the Creative Commons Attribution 4.0 International (
Usage/Advanced-usage.md
Usage/Configuration-settings.md

.. toctree::
:maxdepth: 3
:caption: Customizing output

Customizing/Module-Values.md

.. toctree::
:maxdepth: 3
:caption: Built-In Output Modules
Expand Down
5 changes: 4 additions & 1 deletion src/QROptionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,9 @@ trait QROptionsTrait{

/**
* String substitute for dark
*
* @see https://en.wikipedia.org/wiki/Block_Elements
* @see https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
*/
protected string $textDark = '██';

Expand All @@ -450,7 +453,7 @@ trait QROptionsTrait{
*/

/**
* Measurement unit for `FPDF` output: pt, mm, cm, in (defaults to "pt")
* Measurement unit for `FPDF` output: `pt`, `mm`, `cm`, `in` (default: `pt`)
*
* @see FPDF::__construct()
*/
Expand Down

0 comments on commit 171f0d9

Please sign in to comment.