Skip to content

Commit 171f0d9

Browse files
committed
📖
1 parent 97ee549 commit 171f0d9

File tree

7 files changed

+244
-4
lines changed

7 files changed

+244
-4
lines changed

docs/Customizing/Module-Values.md

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# Module values
2+
3+
## Basics
4+
5+
The QR Code matrix is a 2-dimensional array of numerical values that hold a bit mask for
6+
each QR pixel ("module" as per specification), the so-called "module type" or `$M_TYPE`, which is represented by
7+
[the `QRMatrix::M_*` constants](https://chillerlan.github.io/php-qrcode/classes/chillerlan-QRCode-Data-QRMatrix.html#toc-constants).
8+
You can assign different values for the several [function patterns](../Appendix/Terminology.md#function-patterns) to colorize them or even draw pixel-art.
9+
10+
11+
## Assigning values
12+
13+
To map the values and properly render the modules for the given `QROutputInterface`, it may be necessary to overwrite the
14+
[default values](https://chillerlan.github.io/php-qrcode/classes/chillerlan-QRCode-Output-QROutputInterface.html#constant_DEFAULT_MODULE_VALUES),
15+
that are replaced by the user defined values in `QROptions::$moduleValues` during the render process.
16+
17+
The map of `QRMatrix::M_*` constants => default values looks similar to the following:
18+
19+
```php
20+
$options->moduleValues = [
21+
// light
22+
QRMatrix::M_NULL => false,
23+
QRMatrix::M_DARKMODULE_LIGHT => false,
24+
QRMatrix::M_DATA => false,
25+
QRMatrix::M_FINDER => false,
26+
QRMatrix::M_SEPARATOR => false,
27+
QRMatrix::M_ALIGNMENT => false,
28+
QRMatrix::M_TIMING => false,
29+
QRMatrix::M_FORMAT => false,
30+
QRMatrix::M_VERSION => false,
31+
QRMatrix::M_QUIETZONE => false,
32+
QRMatrix::M_LOGO => false,
33+
QRMatrix::M_FINDER_DOT_LIGHT => false,
34+
QRMatrix::M_TEST => false,
35+
// dark
36+
QRMatrix::M_DARKMODULE => true,
37+
QRMatrix::M_DATA_DARK => true,
38+
QRMatrix::M_FINDER_DARK => true,
39+
QRMatrix::M_SEPARATOR_DARK => true,
40+
QRMatrix::M_ALIGNMENT_DARK => true,
41+
QRMatrix::M_TIMING_DARK => true,
42+
QRMatrix::M_FORMAT_DARK => true,
43+
QRMatrix::M_VERSION_DARK => true,
44+
QRMatrix::M_QUIETZONE_DARK => true,
45+
QRMatrix::M_LOGO_DARK => true,
46+
QRMatrix::M_FINDER_DOT => true,
47+
QRMatrix::M_TEST_DARK => true,
48+
];
49+
```
50+
51+
Not all the module values need to be specified - missing values will be filled with the internal default values
52+
for `true` (dark) and `false` (light) respectively. The `QROutputInterface` inheritors implement a `moduleValueIsValid()`
53+
method that checks if the given value is valid for that particular class:
54+
55+
```php
56+
// set an initial value that acts as default
57+
$dark = 'rgba(0, 0, 0, 0.5)';
58+
59+
// try to receive user input
60+
if(QRMarkupSVG::moduleValueIsValid($_GET['qr_dark'])){
61+
// module values for HTML, SVG and other markup may need special treatment,
62+
// e.g. only accept hexadecimal values from user input
63+
// as moduleValueIsValid() just checks for the general syntax
64+
$dark = sanitize_user_input($_GET['qr_dark']);
65+
}
66+
67+
$options->moduleValues = [
68+
QRMatrix::M_DATA_DARK => $dark,
69+
QRMatrix::M_FINDER_DARK => $dark,
70+
QRMatrix::M_ALIGNMENT_DARK => $dark,
71+
QRMatrix::M_FINDER_DOT => $dark,
72+
];
73+
```
74+
75+
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)):
76+
77+
```php
78+
// for HTML, SVG and ImageMagick
79+
$options->moduleValues = [
80+
QRMatrix::M_DATA => '#ffffff',
81+
QRMatrix::M_DATA_DARK => '#000000',
82+
// ...
83+
];
84+
85+
// for the GdImage, EPS and FPDF output types
86+
$options->moduleValues = [
87+
QRMatrix::M_DATA => [255, 255, 255],
88+
QRMatrix::M_DATA_DARK => [0, 0, 0],
89+
// ...
90+
];
91+
92+
// for string/text output
93+
$options->moduleValues = [
94+
QRMatrix::M_DATA => '░░',
95+
QRMatrix::M_DATA_DARK => '██',
96+
// ...
97+
];
98+
```
99+
100+
101+
## Handling in your own `QROutputInterface`
102+
103+
### Setting module values
104+
105+
[`QROutputAbstract::setModuleValues()`](https://chillerlan.github.io/php-qrcode/classes/chillerlan-QRCode-Output-QROutputAbstract.html#method_setModuleValues)
106+
calls the 3 abstract methods `moduleValueIsValid()`, `getModuleValue()` and `getDefaultModuleValue()` to fill the internal
107+
module value map with the values given via `QROptions::$moduleValues`:
108+
109+
```php
110+
protected function setModuleValues():void{
111+
112+
foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){
113+
$value = ($this->options->moduleValues[$M_TYPE] ?? null);
114+
115+
$this->moduleValues[$M_TYPE] = $this->moduleValueIsValid($value)
116+
? $this->getModuleValue($value)
117+
: $this->getDefaultModuleValue($defaultValue);
118+
}
119+
120+
}
121+
```
122+
123+
In the following example we'll create these methods for the `GdImage` output.
124+
Since [`imagecolorallocate()`](https://www.php.net/manual/function.imagecolorallocate) and other GD functions accept 3 values
125+
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)]`).
126+
127+
First we need to validate the input:
128+
129+
```php
130+
protected function moduleValueIsValid($value):bool{
131+
132+
// nowhere near valid
133+
if(!is_array($value) || count($value) !== 3){
134+
return false;
135+
}
136+
137+
// now iterate over the values
138+
foreach($value as $color){
139+
140+
// non-integers won't work
141+
if(!is_int($color)){
142+
return false;
143+
}
144+
145+
// a strict check - we could also just ignore outliers and clamp the values instead
146+
if($color < 0 || $color > 255){
147+
return false;
148+
}
149+
}
150+
151+
return true; // yay!
152+
}
153+
```
154+
155+
Now we can prepare the value:
156+
157+
```php
158+
protected function getModuleValue($value):array{
159+
// we call array_values() so we don't run into string-key related issues
160+
return array_map(fn(int $val):int => max(0, min(255, $val)), array_values($value));
161+
}
162+
```
163+
164+
And finally we need to provide default values:
165+
166+
```php
167+
protected function getDefaultModuleValue(bool $isDark):array{
168+
return $isDark ? [0, 0, 0] : [255, 255, 255];
169+
}
170+
```
171+
172+
Now that everything is ready and set, we can use the values in our GD functions:
173+
174+
```php
175+
$color = imagecolorallocate($this->image, ...$this->moduleValues[$M_TYPE]);
176+
```
177+
178+
179+
### Using the module values
180+
181+
The state of the `$M_TYPE` is set with the `QRMatrix::IS_DARK` constant:
182+
183+
```php
184+
// set to dark (true) with bitwise OR:
185+
$M_TYPE = ($M_TYPE | QRMatrix::IS_DARK);
186+
187+
// set to light (false) with bitwise AND NOT
188+
$M_TYPE = ($M_TYPE & ~QRMatrix::IS_DARK);
189+
190+
// toggle the opposite state with bitwise XOR
191+
$M_TYPE = ($M_TYPE ^ QRMatrix::IS_DARK);
192+
```
193+
194+
You can manually check whether the module is dark:
195+
196+
```php
197+
($value & QRMatrix::IS_DARK) === QRMatrix::IS_DARK;
198+
```
199+
200+
However it is much more convenient to use the `QRMatrix` methods for that:
201+
202+
```php
203+
for($y = 0; $y < $this->moduleCount; $y++){ // rows
204+
for($x = 0; $x < $this->moduleCount; $x++){ // columns
205+
// sets current module as dark (true) with the M_DATA type
206+
$this->matrix->set($x, $y, true, QRMatrix::M_DATA);
207+
208+
// -> true (shortcut for checkType($x, $y, QRMatrix::IS_DARK))
209+
$this->matrix->check($x, $y);
210+
211+
// -> true (current module is of type M_DATA)
212+
$this->matrix->checkType($x, $y, QRMatrix::M_DATA);
213+
214+
// -> true (current module is of type IS_DARK)
215+
$this->matrix->checkType($x, $y, QRMatrix::IS_DARK);
216+
217+
// -> false, type is M_DATA
218+
$this->matrix->checkTypeIn($x, $y, [QRMatrix::M_FINDER_DARK, QRMatrix::M_ALIGNMENT]);
219+
}
220+
}
221+
```

docs/Readme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ The markdown sources for the [Read the Docs online manual](https://php-qrcode.re
6464
- [Configuration settings](./Usage/Configuration-settings.md)
6565

6666

67+
### Customizing output
68+
69+
- [Module values](./Customizing/Module-Values.md)
70+
71+
6772
### Built-In Output Modules
6873

6974
- [QREps](./Built-In-Output/QREps.md)

docs/Usage/Advanced-usage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
## Configuration via `QROptions`
44

55
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.
6-
A list with all available `QROptions` can be found under [cnfiguration settings](../Usage/Configuration-settings.md).
6+
A list with all available `QROptions` can be found under [configuration settings](../Usage/Configuration-settings.md).
77

88
```php
99
$options = new QROptions;

docs/Usage/Configuration-settings.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,11 @@ Sets the value for the "preserveAspectRatio" on the `<svg>` element
389389

390390
String substitute for dark
391391

392+
**See also:**
393+
394+
- [en.wikipedia.org/wiki/Block_Elements](https://en.wikipedia.org/wiki/Block_Elements)
395+
- [en.wikipedia.org/wiki/ANSI_escape_code#8-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit)
396+
392397

393398
## textLight
394399

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

408413
## fpdfMeasureUnit
409414

410-
Measurement unit for `FPDF` output: pt, mm, cm, in (defaults to "pt")
415+
Measurement unit for `FPDF` output: `pt`, `mm`, `cm`, `in` (default: `pt`)
411416

412417
**See also:**
413418

docs/Usage/Overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Overview
22

3-
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>
3+
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.
44
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).
55

66

docs/index.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ This work is licensed under the Creative Commons Attribution 4.0 International (
2222
Usage/Advanced-usage.md
2323
Usage/Configuration-settings.md
2424

25+
.. toctree::
26+
:maxdepth: 3
27+
:caption: Customizing output
28+
29+
Customizing/Module-Values.md
30+
2531
.. toctree::
2632
:maxdepth: 3
2733
:caption: Built-In Output Modules

src/QROptionsTrait.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,9 @@ trait QROptionsTrait{
427427

428428
/**
429429
* String substitute for dark
430+
*
431+
* @see https://en.wikipedia.org/wiki/Block_Elements
432+
* @see https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
430433
*/
431434
protected string $textDark = '██';
432435

@@ -450,7 +453,7 @@ trait QROptionsTrait{
450453
*/
451454

452455
/**
453-
* Measurement unit for `FPDF` output: pt, mm, cm, in (defaults to "pt")
456+
* Measurement unit for `FPDF` output: `pt`, `mm`, `cm`, `in` (default: `pt`)
454457
*
455458
* @see FPDF::__construct()
456459
*/

0 commit comments

Comments
 (0)