smiley 2 лет назад
Родитель
Сommit
171f0d97da

+ 221 - 0
docs/Customizing/Module-Values.md

@@ -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 - 0
docs/Readme.md

@@ -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)

+ 1 - 1
docs/Usage/Advanced-usage.md

@@ -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;

+ 6 - 1
docs/Usage/Configuration-settings.md

@@ -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
 
@@ -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:**
 

+ 1 - 1
docs/Usage/Overview.md

@@ -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).
 
 

+ 6 - 0
docs/index.rst

@@ -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

+ 4 - 1
src/QROptionsTrait.php

@@ -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 = '██';
 
@@ -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()
 	 */