This commit is contained in:
smiley
2023-10-27 23:39:31 +02:00
parent ff147426a1
commit 49b0c399c8
11 changed files with 227 additions and 54 deletions
@@ -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
View File
@@ -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).
-2
View File
@@ -96,8 +96,6 @@ echo $imagick->getImageBlob();
| `$imageTransparent` | `bool` |
| `$imagickFormat` | `string` |
| `$keepAsSquare` | `array` |
| `$markupDark` | `string` |
| `$markupLight` | `string` |
| `$outputBase64` | `bool` |
| `$quality` | `int` |
| `$returnResource` | `bool` |
-5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;