smiley 2 years ago
parent
commit
49b0c399c8

+ 78 - 0
docs/Appendix/Performance-considerations.md

@@ -0,0 +1,78 @@
+# Performance considerations
+
+Generating a QR Code is not a trivial task - it is a combination of countless complex mathematical operations.
+
+This library seeks not to be the fastest QR Code generator, but instead to provide flexibility and user friendlyness,
+which in turn comes with a slight performance cost.
+
+
+## Version
+
+The [version of the QR symbol](./Terminology.md#version) is one of the major performance factors as it
+determines the size of the symbol and therefore the amount of data that can be stored. Iterating over the internal
+representation of the matrix takes more time with increasing size and the internals iterate over the matrix a LOT.
+
+Because of that you want of course to select the smallest possible version for the given data, which the encoder does by default.
+However, sometimes the possibly varying size of the symbol may not be desired and you want to choose a fixed size, in which case
+you should determine the maximum size of the input data and choose a version that fits.
+
+
+## Ecc level
+
+Another factor is the [ECC level](./Terminology.md#ecc-error-correction-coding) that determines the error correction capacity. The default setting is the lowest capacity (L, 7%)
+which allows the highest amount of data to be stored and which is good enough for e.g. on-screen display or poster prints.
+ECC level H on the other hand allows for up to 30% error correction capacity, which is great for "high risk" applications such as prints on mail.
+With increasing error correction capacity, the maximum amount of data a symbol can hold decreases, and a higher version number may be necessary.
+
+
+## Data mode
+
+By default, the encoder auto-detects the best [mode for data encoding](Terminology.md#mode) (numeric, alphanumeric, kanji, hanzi or 8-bit binary)
+and depending on the length of the given data, the detection costs an increasing amount of time. To circumvent this,
+you can call one of the "add segment" methods on the `QRCode` instance, for example: `$qrcode->addByteSegment($data)`.
+
+Generally, using 8-bit binary mode (or just "byte mode") is the fast and fail-safe mode for any kind of data, and with
+[ECI](https://en.wikipedia.org/wiki/Extended_Channel_Interpretation) it even offers support for character sets other than UTF-8.
+So, unless you want to fit a large amount of japanese or chinese characters into a QR symbol of a certain version,
+encoding those characters as 3 or 4 byte UTF-8 may still be faster in 8-bit byte than in the "compressed" 13-bit double byte modes.
+
+
+## Mask pattern
+
+[Evaluating the QR symbol](./Terminology.md#data-masking) in order to pick the right [mask pattern](./Terminology.md#mask-pattern)
+is a complex and costly operation that is necessary to ensure the symbol is readable. Although [there is an option](../Usage/Configuration-settings.md#maskpattern)
+to override the evaluation and manually set a mask pattern, this is not recommended unless you know exactly what you're doing
+as it can render a QR symbol unreadable.
+
+The table below shows the performance impact (in miliseconds) of the mask pattern evaluation for each version, the times may vary between systems.
+
+| version   |       1 |       2 |       3 |       4 |       5 |       6 |       7 |       8 |       9 |      10 |
+|-----------|--------:|--------:|--------:|--------:|--------:|--------:|--------:|--------:|--------:|--------:|
+| **1-10**  |   4.414 |   5.697 |   7.986 |   9.221 |  10.877 |  11.293 |  13.901 |  15.563 |  18.142 |  20.501 |
+| **11-20** |  22.662 |  27.779 |  29.622 |  33.017 |  36.358 |  39.712 |  43.685 |  47.121 |  51.389 |  57.865 |
+| **21-30** |  59.753 |  68.502 |  68.523 |  72.866 |  78.245 |  83.593 |  88.327 |  94.921 | 103.394 | 106.358 |
+| **31-40** | 113.311 | 120.484 | 126.215 | 132.931 | 139.783 | 145.617 | 170.576 | 165.996 | 167.365 | 175.821 |
+
+
+## Output
+
+Output rendering depends heavily on the size of the QR matrix, the desired type and the underlying libraries and/or PHP extensions.
+Especially the rendering of raster images through GD or ImagMagick can be very slow, depending on [the scale setting](../Usage/Configuration-settings.md#scale),
+filters and image type.
+
+Below a comparison of the performance for the several built-in output classes (times in miliseconds, scale = 5):
+
+|                   |     v5 |    v10 |     v15 |     v20 |     v25 |     v30 |     v35 |     v40 |
+|-------------------|-------:|-------:|--------:|--------:|--------:|--------:|--------:|--------:|
+| **QRMarkupSVG**   |  3.732 |  8.645 |  13.846 |  21.127 |  32.842 |  43.753 |  56.584 |  73.885 |
+| **QRMarkupHTML**  |  0.522 |  1.308 |   2.062 |   2.761 |   3.907 |   5.201 |   7.931 |   9.572 |
+| **QRGdImageBMP**  |  5.998 | 12.541 |  20.728 |  32.336 |  46.345 |  62.842 |  81.555 | 106.482 |
+| **QRGdImageGIF**  |  3.427 |  6.817 |  12.226 |  17.925 |  25.453 |  35.136 |  44.706 |  57.477 |
+| **QRGdImageJPEG** |  2.284 |  4.882 |   8.161 |  12.097 |  17.333 |  23.862 |  30.327 |  40.226 |
+| **QRGdImagePNG**  |  4.523 |  9.377 |  16.581 |  26.207 |  36.516 |  49.066 |  63.765 |  82.074 |
+| **QRGdImageWEBP** |  8.211 | 17.367 |  30.079 |  47.095 |  69.668 |  91.378 | 119.869 | 150.288 |
+| **QRStringJSON**  |  0.043 |  0.066 |   0.107 |   0.158 |   0.215 |   0.301 |   0.369 |   0.492 |
+| **QRStringText**  |  0.229 |  0.387 |   0.628 |   0.952 |   1.312 |   1.759 |   2.329 |   3.045 |
+| **QRImagick**     | 37.694 | 68.808 | 114.415 | 172.962 | 242.338 | 325.085 | 419.999 | 529.897 |
+| **QRFpdf**        |  6.578 | 12.466 |  21.169 |  33.021 |  45.469 |  61.198 |  80.092 | 100.059 |
+| **QREps**         |  1.269 |  2.694 |   4.515 |   6.933 |  11.049 |  14.181 |  20.799 |  25.886 |

+ 4 - 4
docs/Appendix/Terminology.md

@@ -20,15 +20,15 @@ the module is located, with counting commencing at 0. Module `(0, 0)` is therefo
 
 ### Module
 
-A *module* represents a single square "pixel" (not to confuse with pixels in a raster image or screen) in the matrix.
-A dark module is a binary one and a light module is a binary zero.
+A *module* represents a single square "pixel" in the matrix (not to confuse with pixels in a raster image or screen).
+A dark module represents a binary one and a light module represents a binary zero.
 
 
 ### Version
 
 The *version* of a QR symbol determines the side length of the matrix (and therefore the maximum capacity of code words),
-ranging from 21×21 modules at version 1 to 177×177 modules at version 40; the module count increases in steps of 4 and can
-be calculated by `4 * version + 17`.
+ranging from 21×21 modules (441 total) at version 1 to 177×177 modules (31329 total) at version 40.
+The module count increases in steps of 4 and can be calculated by `4 * version + 17`.
 
 The maximum capacity for each version, mode and ECC level can be found in [this table (qrcode.com)](https://www.qrcode.com/en/about/version.html).
 

+ 0 - 2
docs/Built-In-Output/QRImagick.md

@@ -96,8 +96,6 @@ echo $imagick->getImageBlob();
 | `$imageTransparent`    | `bool`   |
 | `$imagickFormat`       | `string` |
 | `$keepAsSquare`        | `array`  |
-| `$markupDark`          | `string` |
-| `$markupLight`         | `string` |
 | `$outputBase64`        | `bool`   |
 | `$quality`             | `int`    |
 | `$returnResource`      | `bool`   |

+ 0 - 5
docs/Built-In-Output/QRMarkupHTML.md

@@ -17,9 +17,6 @@ $options = new QROptions;
 
 $options->outputType   = QROutputInterface::MARKUP_HTML;
 $options->cssClass     = 'qrcode';
-// default values for unassigned module types
-$options->markupDark   = '#555';
-$options->markupLight  = '#CCC';
 $options->moduleValues = [
 	// finder
 	QRMatrix::M_FINDER_DARK    => '#A71111', // dark (true)
@@ -88,8 +85,6 @@ header('Content-type: text/html');
 |----------------|----------|
 | `$cssClass`    | `string` |
 | `$eol`         | `string` |
-| `$markupDark`  | `string` |
-| `$markupLight` | `string` |
 
 
 ### Options that have no effect

+ 25 - 28
docs/Built-In-Output/QRMarkupSVG.md

@@ -11,21 +11,19 @@ Set the options:
 ```php
 $options = new QROptions;
 
-$options->version             = 7;
-$options->outputType          = QROutputInterface::MARKUP_SVG;
+$options->version              = 7;
+$options->outputType           = QROutputInterface::MARKUP_SVG;
 // if set to false, the light modules won't be rendered
-$options->drawLightModules    = true;
-// empty the default value to remove the fill* and opacity* attributes from the <path> elements
-$options->markupDark          = '';
-$options->markupLight         = '';
+$options->drawLightModules     = true;
+$options->svgUseFillAttributes = true;
 // draw the modules as circles isntead of squares
-$options->drawCircularModules = true;
-$options->circleRadius        = 0.4;
+$options->drawCircularModules  = true;
+$options->circleRadius         = 0.4;
 // connect paths to avoid render glitches
 // @see https://github.com/chillerlan/php-qrcode/issues/57
-$options->connectPaths        = true;
+$options->connectPaths         = true;
 // keep modules of these types as square
-$options->keepAsSquare        = [
+$options->keepAsSquare         = [
 	QRMatrix::M_FINDER_DARK,
 	QRMatrix::M_FINDER_DOT,
 	QRMatrix::M_ALIGNMENT_DARK,
@@ -72,24 +70,23 @@ printf('<img alt="%s" src="%s" />', $alt, $out);
 
 ## Options that affect this module
 
-| property                  | type           |
-|---------------------------|----------------|
-| `$circleRadius`           | `float`        |
-| `$connectPaths`           | `bool`         |
-| `$cssClass`               | `string`       |
-| `$drawCircularModules`    | `bool`         |
-| `$drawLightModules`       | `bool`         |
-| `$eol`                    | `string`       |
-| `$excludeFromConnect`     | `array`        |
-| `$keepAsSquare`           | `array`        |
-| `$markupDark`             | `string`       |
-| `$markupLight`            | `string`       |
-| `$outputBase64`           | `bool`         |
-| `$svgAddXmlHeader`        | `bool`         |
-| `$svgDefs`                | `string`       |
-| `$svgOpacity`             | `float`        |
-| `$svgPreserveAspectRatio` | `string`       |
-| `$svgViewBoxSize`         | `int\|null`    |
+| property                  | type        |
+|---------------------------|-------------|
+| `$circleRadius`           | `float`     |
+| `$connectPaths`           | `bool`      |
+| `$cssClass`               | `string`    |
+| `$drawCircularModules`    | `bool`      |
+| `$drawLightModules`       | `bool`      |
+| `$eol`                    | `string`    |
+| `$excludeFromConnect`     | `array`     |
+| `$keepAsSquare`           | `array`     |
+| `$outputBase64`           | `bool`      |
+| `$svgAddXmlHeader`        | `bool`      |
+| `$svgDefs`                | `string`    |
+| `$svgOpacity`             | `float`     |
+| `$svgPreserveAspectRatio` | `string`    |
+| `$svgViewBoxSize`         | `int\|null` |
+| `$svgUseFillAttributes`   | `bool`      |
 
 
 ### Options that have no effect

+ 2 - 2
docs/Customizing/QROutputAbstract.md

@@ -26,8 +26,8 @@ The finalized map of `$M_TYPE` to value for the current output. This map is gene
 ### 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`.
+Currently, the following values are copied via `copyVars()` during invocation: `$connectPaths`, `$excludeFromConnect`, `$eol`,
+`$drawLightModules`, `$drawCircularModules`, `$keepAsSquare`, `$circleRadius` (and additionally `$circleDiameter`).
 
 
 ## Methods

+ 2 - 1
docs/Readme.md

@@ -83,9 +83,10 @@ The markdown sources for the [Read the Docs online manual](https://php-qrcode.re
 
 ### Appendix
 
-- [How to contribute](./Appendix/Contribute.md)
 - [Terminology](./Appendix/Terminology.md)
 - [Popular content and URI schemes](./Appendix/URI-Content.md)
+- [Performance considerations](./Appendix/Performance-considerations.md)
+- [How to contribute](./Appendix/Contribute.md)
 - [License](./Appendix/License.rst)
 
 

+ 104 - 5
docs/Usage/Configuration-settings.md

@@ -6,6 +6,7 @@ QR Code version number
 
 `1 ... 40` or `Version::AUTO` (default)
 
+
 **See also:**
 
 - `\chillerlan\QRCode\Common\Version`
@@ -36,6 +37,7 @@ Error correct level
 - `Q` => 25%
 - `H` => 30%
 
+
 **See also:**
 
 - `\chillerlan\QRCode\Common\EccLevel`
@@ -48,6 +50,7 @@ Mask Pattern to use (no value in using, mostly for unit testing purposes)
 
 `0 ... 7` or `MaskPattern::PATTERN_AUTO` (default)
 
+
 **See also:**
 
 - `\chillerlan\QRCode\Common\MaskPattern`
@@ -57,6 +60,7 @@ Mask Pattern to use (no value in using, mostly for unit testing purposes)
 
 Add a "quiet zone" (margin) according to the QR code spec
 
+
 **See also:**
 
 - [www.qrcode.com/en/howto/code.html](https://www.qrcode.com/en/howto/code.html)
@@ -87,6 +91,9 @@ The built-in output type
 - `QROutputInterface::FPDF`
 - `QROutputInterface::CUSTOM`
 
+
+**Deprecated:** 5.0.0 see issue #223
+
 **See also:**
 
 - `\chillerlan\QRCode\Output\QREps`
@@ -96,6 +103,7 @@ The built-in output type
 - `\chillerlan\QRCode\Output\QRMarkupHTML`
 - `\chillerlan\QRCode\Output\QRMarkupSVG`
 - `\chillerlan\QRCode\Output\QRString`
+- [github.com/chillerlan/php-qrcode/issues/223](https://github.com/chillerlan/php-qrcode/issues/223)
 
 
 ## outputInterface
@@ -104,6 +112,9 @@ The FQCN of the custom `QROutputInterface`
 
 if `QROptions::$outputType` is set to `QROutputInterface::CUSTOM` (default: `null`)
 
+**Deprecated:** 5.0.0 the nullable type will be removed in future versions
+and the default value will be set to `QRMarkupSVG::class`
+
 
 ## returnResource
 
@@ -116,6 +127,7 @@ Return the image resource instead of a render if applicable.
 This option overrides/ignores other output settings, such as `QROptions::$cachefile`
 and `QROptions::$outputBase64`. (default: `false`)
 
+
 **See also:**
 
 - `\chillerlan\QRCode\Output\QROutputInterface::dump()`
@@ -128,6 +140,7 @@ Optional cache file path `/path/to/cache.file`
 Please note that the `$file` parameter in `QRCode::render()` and `QRCode::renderMatrix()`
 takes precedence over the `QROptions::$cachefile` value. (default: `null`)
 
+
 **See also:**
 
 - `\chillerlan\QRCode\QRCode::render()`
@@ -140,6 +153,7 @@ Toggle base64 data URI or raw data output (if applicable)
 
 (default: `true`)
 
+
 **See also:**
 
 - `\chillerlan\QRCode\Output\QROutputAbstract::toBase64DataURI()`
@@ -168,6 +182,7 @@ Whether to invert the matrix (reflectance reversal)
 
 (default: `false`)
 
+
 **See also:**
 
 - `\chillerlan\QRCode\Data\QRMatrix::invert()`
@@ -191,6 +206,7 @@ using `imagefilledellipse()` and then scaled back to the expected size
 
 No effect in: `QREps`, `QRFpdf`, `QRMarkupHTML`
 
+
 **See also:**
 
 - [php.net: `\imagefilledellipse()`](https://www.php.net/manual/function.imagefilledellipse)
@@ -216,6 +232,7 @@ Specifies which module types to exclude when `QROptions::$drawCircularModules` i
 
 Whether to connect the paths for the several module types to avoid weird glitches when using gradients etc.
 
+
 **See also:**
 
 - [github.com/chillerlan/php-qrcode/issues/57](https://github.com/chillerlan/php-qrcode/issues/57)
@@ -234,6 +251,7 @@ Module values map
 - `QREps`, `QRFpdf`, `QRGdImage`: `[R, G, B]` // 0-255
 - `QREps`: `[C, M, Y, K]` // 0-255
 
+
 **See also:**
 
 - `\chillerlan\QRCode\Output\QROutputAbstract::setModuleValues()`
@@ -243,6 +261,7 @@ Module values map
 
 Toggles logo space creation
 
+
 **See also:**
 
 - `\chillerlan\QRCode\QRCode::addMatrixModifications()`
@@ -284,6 +303,7 @@ Toggle transparency
 
 - `QRGdImage` and `QRImagick`: the given `QROptions::$transparencyColor` is set as transparent
 
+
 **See also:**
 
 - [github.com/chillerlan/php-qrcode/discussions/121](https://github.com/chillerlan/php-qrcode/discussions/121)
@@ -299,6 +319,7 @@ Defaults to `QROptions::$bgColor`.
 - `QRImagick`: `"color_str"`, this color is set in `Imagick::transparentPaintImage()`
 
 
+
 **See also:**
 
 - [php.net: `\imagecolortransparent()`](https://www.php.net/manual/function.imagecolortransparent)
@@ -311,11 +332,12 @@ Compression quality
 
 The given value depends on the used output type:
 
-- `QROutputInterface::GDIMAGE_BMP`:  `[0...1]`
-- `QROutputInterface::GDIMAGE_JPG`:  `[0...100]`
-- `QROutputInterface::GDIMAGE_WEBP`: `[0...9]`
-- `QROutputInterface::GDIMAGE_PNG`:  `[0...100]`
-- `QROutputInterface::IMAGICK`:      `[0...100]`
+- `QRGdImageBMP`:  `[0...1]`
+- `QRGdImageJPEG`: `[0...100]`
+- `QRGdImageWEBP`: `[0...9]`
+- `QRGdImagePNG`:  `[0...100]`
+- `QRImagick`:     `[0...100]`
+
 
 **See also:**
 
@@ -326,10 +348,23 @@ The given value depends on the used output type:
 - [php.net: `\Imagick::setImageCompressionQuality()`](https://www.php.net/manual/imagick.setimagecompressionquality)
 
 
+## gdImageUseUpscale
+
+Toggles the usage of internal upscaling when `QROptions::$drawCircularModules` is set to `true` and
+`QROptions::$scale` is less than 20
+
+
+**See also:**
+
+- `\chillerlan\QRCode\Output\QRGdImage::createImage()`
+- [github.com/chillerlan/php-qrcode/issues/23](https://github.com/chillerlan/php-qrcode/issues/23)
+
+
 ## imagickFormat
 
 Imagick output format
 
+
 **See also:**
 
 - [php.net: `\Imagick::setImageFormat()`](https://www.php.net/manual/imagick.setimageformat)
@@ -352,6 +387,7 @@ Whether to add an XML header line or not, e.g. to embed the SVG directly in HTML
 
 Anything in the SVG `<defs>` tag
 
+
 **See also:**
 
 - [developer.mozilla.org/en-US/docs/Web/SVG/Element/defs](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs)
@@ -361,6 +397,7 @@ Anything in the SVG `<defs>` tag
 
 Sets the value for the "preserveAspectRatio" on the `<svg>` element
 
+
 **See also:**
 
 - [developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio)
@@ -373,6 +410,7 @@ Whether to use the SVG `fill` attributes
 If set to `true` (default), the `fill` attribute will be set with the module value for the `<path>` element's `$M_TYPE`.
 When set to `false`, the module values map will be ignored and the QR Code may be styled via CSS.
 
+
 **See also:**
 
 - [developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill)
@@ -383,6 +421,16 @@ When set to `false`, the module values map will be ignored and the QR Code may b
 An optional line prefix, e.g. empty space to align the QR Code in a console
 
 
+## jsonFlags
+
+Sets the flags to use for the `json_encode()` call
+
+
+**See also:**
+
+- [www.php.net/manual/json.constants.php](https://www.php.net/manual/json.constants.php)
+
+
 ## jsonAsBooleans
 
 Whether to return matrix values in JSON as booleans or `$M_TYPE` integers
@@ -392,6 +440,7 @@ Whether to return matrix values in JSON as booleans or `$M_TYPE` integers
 
 Measurement unit for `FPDF` output: `pt`, `mm`, `cm`, `in` (default: `pt`)
 
+
 **See also:**
 
 - `FPDF::__construct()`
@@ -407,9 +456,59 @@ Use Imagick (if available) when reading QR Codes
 Grayscale the image before reading
 
 
+## readerInvertColors
+
+Invert the colors of the image
+
+
 ## readerIncreaseContrast
 
 Increase the contrast before reading
 
 note that applying contrast works different in GD and Imagick, so mileage may vary
 
+
+## imageBase64
+
+**Deprecated:** 5.0.0 use QROptions::$outputBase64 instead
+
+**See also:**
+
+- `       \chillerlan\QRCode\QROptions::$outputBase64`
+
+
+## jpegQuality
+
+**Deprecated:** 5.0.0 use QROptions::$quality instead
+
+**See also:**
+
+- `       \chillerlan\QRCode\QROptions::$quality`
+
+
+## pngCompression
+
+**Deprecated:** 5.0.0 use QROptions::$quality instead
+
+**See also:**
+
+- `       \chillerlan\QRCode\QROptions::$quality`
+
+
+## imageTransparencyBG
+
+**Deprecated:** 5.0.0 use QROptions::$transparencyColor instead
+
+**See also:**
+
+- `       \chillerlan\QRCode\QROptions::$transparencyColor`
+
+
+## imagickBG
+
+**Deprecated:** 5.0.0 use QROptions::$bgColor instead
+
+**See also:**
+
+- `       \chillerlan\QRCode\QROptions::$bgColor`
+

+ 2 - 1
docs/index.rst

@@ -45,8 +45,9 @@ This work is licensed under the Creative Commons Attribution 4.0 International (
    :maxdepth: 3
    :caption: Appendix
 
-   Appendix/Contribute.md
    Appendix/Terminology.md
    Appendix/URI-Content.md
+   Appendix/Performance-considerations.md
+   Appendix/Contribute.md
    Appendix/License.md
 

+ 8 - 4
docs/qroptions-doc.php

@@ -24,9 +24,9 @@ foreach($reflectionClass->getProperties(ReflectionProperty::IS_PROTECTED) as $re
 	$docblock = $reflectionProperty->getDocComment();
 
 	// don't document deprecated settings
-	if(str_contains($docblock, '@deprecated')){
-		continue;
-	}
+#	if(str_contains($docblock, '@deprecated')){
+#		continue;
+#	}
 
 	$content[] = sprintf("## %s\n", $reflectionProperty->getName());
 
@@ -44,6 +44,10 @@ foreach($reflectionClass->getProperties(ReflectionProperty::IS_PROTECTED) as $re
 			continue;
 		}
 
+		if(str_contains($line, '@deprecated')){
+			$line = str_replace('@deprecated', '**Deprecated:**', $line);
+		}
+
 		// collect links for "see also"
 		if(str_starts_with($line, '@see')){
 			$see[] = $line;
@@ -56,7 +60,7 @@ foreach($reflectionClass->getProperties(ReflectionProperty::IS_PROTECTED) as $re
 
 	// add a "see also" section
 	if(!empty($see)){
-		$content[] = "**See also:**\n";
+		$content[] = "\n**See also:**\n";
 
 		foreach($see as $line){
 			$line = substr($line, 5); // cut off the "@see "

+ 2 - 2
src/QROptionsTrait.php

@@ -119,9 +119,9 @@ trait QROptionsTrait{
 	 * @see \chillerlan\QRCode\Output\QRMarkupHTML
 	 * @see \chillerlan\QRCode\Output\QRMarkupSVG
 	 * @see \chillerlan\QRCode\Output\QRString
+	 * @see https://github.com/chillerlan/php-qrcode/issues/223
 	 *
-	 * @deprecated 5.0.0 use `QROptions::$outputInterface` instead
-	 * @see        https://github.com/chillerlan/php-qrcode/issues/223
+	 * @deprecated 5.0.0 see issue #223
 	 */
 	protected string $outputType = QROutputInterface::MARKUP_SVG;