mirror of
https://github.com/chillerlan/php-qrcode.git
synced 2026-08-17 12:13:05 +00:00
📖
This commit is contained in:
@@ -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!
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
```
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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'
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user