This commit is contained in:
smiley
2025-11-23 23:26:24 +01:00
parent 5536c26155
commit c55c64dfa0
11 changed files with 209 additions and 120 deletions
-34
View File
@@ -125,40 +125,6 @@ Also, have a look [in the examples folder](https://github.com/chillerlan/php-qrc
</p>
## Reading QR Codes
Using the built-in QR Code reader is pretty straight-forward:
```php
// it's generally a good idea to wrap the reader in a try/catch block because it WILL throw eventually
try{
$result = (new QRCode)->readFromFile('path/to/file.png'); // -> DecoderResult
// you can now use the result instance...
$content = $result->data;
$matrix = $result->getMatrix(); // -> QRMatrix
// ...or simply cast it to string to get the content:
$content = (string)$result;
}
catch(Throwable $e){
// oopsies!
}
```
# Shameless advertising
Hi, please check out some of my other projects that are way cooler than qrcodes!
- [js-qrcode](https://github.com/chillerlan/js-qrcode) - a javascript port of this library
- [php-authenticator](https://github.com/chillerlan/php-authenticator) - a Google Authenticator implementation (see [authenticator example](https://github.com/chillerlan/php-qrcode/blob/main/examples/authenticator.php))
- [php-httpinterface](https://github.com/chillerlan/php-httpinterface) - a PSR-7/15/17/18 implemetation
- [php-oauth](https://github.com/chillerlan/php-oauth) - an OAuth 1/2 client library, fully PSR-7/PSR-17/PSR-18 compatible
- [php-database](https://github.com/chillerlan/php-database) - a database client & querybuilder for MySQL, Postgres, SQLite, MSSQL, Firebird
- [php-tootbot](https://github.com/php-tootbot/tootbot-template) - a Mastodon bot library (see [@dwil](https://github.com/php-tootbot/dwil))
# Disclaimer!
I don't take responsibility for molten CPUs, misled applications, failed log-ins etc.. Use at your own risk!
+24 -22
View File
@@ -44,35 +44,37 @@ is a complex and costly operation that is necessary to ensure the symbol is read
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.
The table below shows the performance impact (in miliseconds) of the mask pattern evaluation for select versions, 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 |
| version | time (ms) |
|---------|----------:|
| **1** | 2.285 |
| **5** | 5.867 |
| **10** | 12.737 |
| **20** | 34.045 |
| **30** | 64.914 |
| **40** | 107.027 |
## 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),
Especially the rendering of raster images through GD or ImageMagick 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 |
| | v5 | v10 | v20 | v30 | v40 |
|-------------------|-------:|-------:|--------:|--------:|--------:|
| **QRMarkupSVG** | 3.732 | 8.645 | 21.127 | 43.753 | 73.885 |
| **QRMarkupHTML** | 0.522 | 1.308 | 2.761 | 5.201 | 9.572 |
| **QRGdImageBMP** | 5.998 | 12.541 | 32.336 | 62.842 | 106.482 |
| **QRGdImageGIF** | 3.427 | 6.817 | 17.925 | 35.136 | 57.477 |
| **QRGdImageJPEG** | 2.284 | 4.882 | 12.097 | 23.862 | 40.226 |
| **QRGdImagePNG** | 4.523 | 9.377 | 26.207 | 49.066 | 82.074 |
| **QRGdImageWEBP** | 8.211 | 17.367 | 47.095 | 91.378 | 150.288 |
| **QRStringJSON** | 0.043 | 0.066 | 0.158 | 0.301 | 0.492 |
| **QRStringText** | 0.229 | 0.387 | 0.952 | 1.759 | 3.045 |
| **QRImagick** | 37.694 | 68.808 | 172.962 | 325.085 | 529.897 |
| **QRFpdf** | 6.578 | 12.466 | 33.021 | 61.198 | 100.059 |
| **QREps** | 1.269 | 2.694 | 6.933 | 14.181 | 25.886 |
+1 -1
View File
@@ -2,7 +2,7 @@
## QR Code
A [*QR code*](https://en.wikipedia.org/wiki/QR_code) (quick-response code) is a type of two-dimensional matrix barcode, invented
A [*QR code*](https://en.wikipedia.org/wiki/QR_code) (quick-response code), sometimes referred to as *QR symbol* or simply just *symbol*, is a type of two-dimensional matrix barcode, invented
in 1994 by Japanese company [Denso Wave](https://www.qrcode.com/en/faq.html#patentH2Title) for labelling automobile parts.
The QR labelling system was applied beyond the automobile industry due to its fast readability and greater storage capacity
compared to standard UPC barcodes.
+2
View File
@@ -62,6 +62,8 @@ The markdown sources for the [Read the Docs online manual](https://php-qrcode.re
- [Quickstart](./Usage/Quickstart.md)
- [Advanced usage](./Usage/Advanced-usage.md)
- [Configuration settings](./Usage/Configuration-settings.md)
- [Reading QR Codes](./Usage/Reading-QRCodes.md)
- [Logos and logo space](./Usage/Logos.md)
### Customizing output
+1 -41
View File
@@ -173,7 +173,7 @@ $output = $qrcode->render();
$qrcode->render(null, '/path/to/qrcode.svg');
```
The [`QRDataModeInterface`](https://github.com/chillerlan/php-qrcode/blob/main/src/Data/QRDataModeInterface.php) offers the `validateString()` method (implemended for `AlphaNum`, `Byte`, `Hanzi`, `Kanji` and `Number`).
The [`QRDataModeInterface`](https://github.com/chillerlan/php-qrcode/blob/main/src/Data/QRDataModeInterface.php) offers the `validateString()` method (implemented for `AlphaNum`, `Byte`, `Hanzi`, `Kanji` and `Number`).
This method is used internally when a data mode is invoked, but it can come in handy if you need to check input data beforehand.
```php
@@ -185,33 +185,6 @@ $qrcode->addHanziSegment($data);
```
### QR Code reader
In some cases it might be necessary to increase the contrast of a QR Code image:
```php
$options->readerUseImagickIfAvailable = true;
$options->readerIncreaseContrast = true;
$options->readerGrayscale = true;
$qrcode = new QRCode($options);
$result = $qrcode->readFromFile('path/to/qrcode.png');
$result = $qrcode->readFromBlob($imagedata);
```
The `QRMatrix` object from the [`DecoderResult`](https://github.com/chillerlan/php-qrcode/blob/main/src/Decoder/DecoderResult.php) can be reused:
```php
$matrix = $result->getQRMatrix();
// ...matrix modification...
$output = (new QRCode($options))->renderMatrix($matrix);
// ...output
```
## Common output options
### Save to file
@@ -266,16 +239,3 @@ $imagick = $qrcode->render($data);
echo $imagick->getImageBlob();
```
### Add a logo space
```php
$options->addLogoSpace = true;
$options->logoSpaceWidth = 9;
$options->logoSpaceHeight = 9;
$options->logoSpaceStartX = 10;
$options->logoSpaceStartY = 10;
```
+3 -1
View File
@@ -191,6 +191,7 @@ Specifies which module types to exclude when `QROptions::$drawCircularModules` i
(default: `[]`)
## connectPaths
Whether to connect the paths for the several module types to avoid weird glitches when using gradients etc.
@@ -215,6 +216,7 @@ Currentty used in `QREps` and `QRMarkupSVG`.
Specify which paths/patterns to exclude from connecting if `QROptions::$connectPaths` is set to `true`
**See also:**
- `\chillerlan\QRCode\QROptionsTrait::$connectPaths`
@@ -229,6 +231,7 @@ Module values map
- `QREps`: `[C, M, Y, K]` // 0-255
**See also:**
- `\chillerlan\QRCode\Output\QROutputAbstract::setModuleValues()`
@@ -296,7 +299,6 @@ 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)
File diff suppressed because one or more lines are too long
-20
View File
@@ -41,26 +41,6 @@ and [configuration settings](../Usage/Configuration-settings.md) for a list of a
Also, have a look [in the examples folder](https://github.com/chillerlan/php-qrcode/tree/main/examples) for some more usage examples.
## Reading QR Codes
Using the built-in QR Code reader is pretty straight-forward:
```php
try{
$result = (new QRCode)->readFromFile('path/to/file.png'); // -> DecoderResult
// you can now use the result instance...
$content = $result->data;
// ...or simply cast the result instance to string to get the content
$content = (string)$result;
}
catch(Throwable $exception){
// handle exception...
}
```
It's generally a good idea to wrap the reading in a try/catch block to handle any errors that may occur in the process.
## Notes
The QR encoder, especially the subroutines for mask pattern testing, can cause high CPU load on increased matrix size.
You can avoid a part of this load by choosing a fast output module, like SVG.
+101
View File
@@ -0,0 +1,101 @@
# Reading QR Codes
## Basic usage
The QR Code reader can be called either from a `QRCode` instance or invoked directly via the `Decoder` class with a `QROptions` (`QRCodeReaderOptionsTrait`) instance.
```php
$options = new QROptions
$options->readerUseImagickIfAvailable = true;
$options->readerIncreaseContrast = true;
$options->readerGrayscale = true;
$options->readerInvertColors = false;
```
The option `QROptions::$readerUseImagickIfAvailable` is exclusive to the `QRCode` instance in order to decide which `LuminanceSourceInterface` to use.
The `QRCode` instance has 3 convenience methods related to the reader:
```php
$qrcode = new QRCode($options)
$result = $qrcode->readFromFile('path/to/qrcode.png');
$result = $qrcode->readFromBlob($imagedata);
// from a luminance source instance
$source = IMagickLuminanceSource::fromBlob($imagedata, $options);
$result = $qrcode->readFromSource($source);
```
## The `LuminanceSourceInterface`
The method `QRCode::readFromSource()` takes a `LuminanceSourceInterface` instance as parameter and is mainly for internal use, as you can invoke and call the decoder directly with it.
Each `LuminanceSourceInterface` has the static convenience methods `fromFile()` and `fromBlob()` that will invoke the instance with the respective parameters, alternatively the instance(s) can be invoked manually:
from an `Imagick` instance:
```php
$imagick = new Imagick;
$imagick->readImageBlob($imagedata);
$source = new IMagickLuminanceSource($imagick, $options);
```
from a `GdImage` instance:
```php
$gdimage = imagecreatefromstring($imagedata);
$source = new GDLuminanceSource($gdimage, $options);
```
## The `Decoder`
The `Decoder` takes a `QROptions` instance as parameter, which currently has no use - it is only handed over for possible future uses.
```php
$result = (new Decoder($options))->decode($source);
```
That is all! The decoder will either return a `DecoderResult` instance or throw an exception.
It is generally a good practice to wrap the reading in a try/catch block:
```php
try{
$result = $qrcode->readFromFile('path/to/file.png'); // -> DecoderResult
// ... do stuff with the result
}
catch(QRCodeDecoderException){
// ... adjust input image (position, contrast, invert, sharpen) and repeat the process
}
```
You can now use the result instance:
```php
$content = $result->data;
// ...or simply cast it to string:
$content = (string)$result;
```
The result instance also holds `Version`, `EccLevel`, `MaskPattern` and `BitBuffer` instances, as well as an array of `FinderPattern` instances,
it also offers a method that returns a `QRMatrix` instance populated with the detected settings:
```php
$matrix = $result->getQRMatrix();
// ...matrix modification...
$output = (new QRCode($options))->renderMatrix($matrix);
// ...dump output
```
## General considerations
The QR Code reader reads the given QR symbol in a single pass, unlike e.g. a reader app on a mobile device with a camera, which repeats the reading process for a sequence of frames from the video input and takes the "best" result.
It means that this reader may fail to properly decode a symbol that reads perfectly fine on a mobile - you'd need to emulate the same process of sequential reading while adjusting the input image to get a similar result.
Further it seems ([per observation](https://github.com/chillerlan/php-qrcode/blob/92346420a5a88aeeb8dc16f731ef1f93331635d3/tests/QRCodeReaderTestAbstract.php#L168-L172)) that the reader favors smaller module sizes (1-2 pixel side length) from version 20 onwards.
The test data set seemed to randomly produce errors depending on the given module scale, independent of the luminance source.
However, scaling down to get a smaller module size isn't the best solution as it may produce additional challenges due to filter artifacts.
+1 -1
View File
@@ -44,7 +44,7 @@ lexers['php-annotations'] = PhpLexer(startinline=True)
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = u'PHP-QRCode'
copyright = u'2023, smiley'
copyright = u'2025, smiley'
author = u'smiley'
epub_author = u'smiley'
+2
View File
@@ -21,6 +21,8 @@ This work is licensed under the Creative Commons Attribution 4.0 International (
Usage/Quickstart.md
Usage/Advanced-usage.md
Usage/Configuration-settings.md
Usage/Reading-QRCodes.md
Usage/Logos.md
.. toctree::
:maxdepth: 3