Metadata-Version: 2.4
Name: qrref
Version: 0.1.0
Summary: QR code generator with a command-line interface for showing, saving and copying generated QR codes.
Project-URL: Homepage, https://github.com/TrulsHenriksson/qrref/
License-Expression: MIT
License-File: LICENSE
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.12
Requires-Dist: matplotlib
Requires-Dist: numpy
Requires-Dist: pillow
Provides-Extra: copy
Requires-Dist: pyperclipimg; extra == 'copy'
Description-Content-Type: text/markdown

# qrref

Python package and reference implementation of the ISO/IEC 18004:2015 Standard for QR codes, with a simple but convenient CLI for showing, saving and copying generated QR codes.

![Sample QR code](sample_qr_code.png)

# Purpose

This is first and foremost a reference implementation, meaning I wanted the code to be readable and well-documented, without lots of magic numbers and tables copied straight from the specification. For those wanting to implement their own QR code generator, or extending one to suit their needs (custom colors, styles, inset images, etc.) this should be a good basis.

Wherever possible, I've chosen to implement the table data as functions instead. This doesn't result in the shortest or fastest implementation, but should explain where the numbers come from better.

The priorities of this project have been as follows, in approximate order of importance.
1. **Referentiability.** The code should adhere closely to the specification.
    - Most functions and tables are accompanied by comments referencing where they can be found in the specification. Look up "ISO/IEC 18004" and you can probably find it somewhere.
2. **Clarity.** The code should be easy to read and understand.
    - Comments and docstrings are mandatory.
    - The code is split up into files with clearly different responsibilities, and should be understandable (mostly) on their own.
3. **Transparency.** Table data should be generated by functions wherever possible. 
    - The implementation could be made shorter by hard-coding certain parts, most notably the coefficients of the generating polynomials for the Solomon-Reed code. This is against the spirit of this project though.
    - Table data is still preferred where a function would be less clear.
4. **Efficiency.** Looping over the entire symbol in Python should be avoided.
    - NumPy is used extensively to speed up generation.

# Usage

Install by running
```bash
$ pip install qrref
```
or to also be able to copy QR codes directly to the clipboard, by running
```bash
$ pip install qrref[copy]
```
This is an optional dependency, since it uses `pyperclipimg` which states in its README: "This module is separate [from pyperclip] because it has some heavy dependencies (pywin32, Quartz, etc.)" Without it, you can still show and save QR codes as png.

You can then `import qrref` and use `qrref.generate_qr_code` in your own code, or use the command-line interface (CLI) directly.

## Examples

Show a QR code with the message "This is a QR code". This is done using Matplotlib, which means that "F" toggles fullscreen and "Q" closes the window. Perfect for quickly throwing up a QR code on a big screen.
```bash
$ py -m qrref "This is a QR code"
```
Save the QR code to `./wikipedia_qr.png`:
```bash
$ py -m qrref "https://wikipedia.org" --png --filename wikipedia_qr
```
Copy the QR code to the clipboard (requires installing with `pip install qrref[copy]`):
```bash
$ py -m qrref "https://wikipedia.org" --copy
```

# Reference details

The generation of a QR code is handled by `qrref.qr.generate_qr_code`. This function is fairly readable and illustrates the process from start to finish:

```python
def generate_qr_code(
    content: str, 
    ec_level: Literal["L", "M", "Q", "H"], 
    version: int | None = None,
):
    if version is None:
        version, modes = select_version(content, ec_level)
    else:
        modes = select_modes(content, version)

    bitstream = encode_mixed(modes, version)
    bytestream = to_data_bytestream(bitstream, version, ec_level)
    blockstream = generate_error_correction_blocks(bytestream, version, ec_level)
    final_bytestream = interleave_blocks(blockstream, version, ec_level)

    symbol = place_bytestream(final_bytestream, version)
    insert_timing_patterns(symbol)
    insert_finder_patterns(symbol)
    insert_alignment_patterns(symbol, version)

    symbol, mask_pattern_id = apply_mask(symbol, version)

    place_format_bits(symbol, generate_format_bits(ec_level, mask_pattern_id))
    if version >= 7:
        place_version_bits(symbol, generate_version_bits(version))

    symbol = expand_quiet_region(symbol)
    return symbol
```

This uses functions split up over several files. Here's a high-level overview of what each file does, in the order they are used in the above function.
1. `qrref/data_analysis.py`: Select the minimum version (qr code size) that the content (input string) fits in. Also select the encoding types that minimizes the length of the data bitstream (numeric data is denser than alphanumeric data, which is denser than byte data).
2. `qrref/data_encoding.py`: Encode the message into a bitstream and group the bits together into bytes.
3. `qrref/error_correction.py`: Generate error correction bytes using the Reed-Solomon codes. In practice, does this by finding polynomial remainders over the Galois Field of order 256 ([wikipedia](https://en.wikipedia.org/wiki/Finite_field_arithmetic)), which also uses `qrref/galois_field.py`. Turn the resulting data and error correction bytes into a bitstream by splitting them into blocks and interleaving those blocks. Also generate the format and version bits after the masking is complete.
4. `qrref/placement.py`: Place the finalized bitstream into the symbol, as well as finder, alignment and timing patterns. After the format and version bits are generated, place those too.
5. `qrref/masking.py`: Find and apply the mask that minimizes undesirable patterns, like long runs of the same color, etc. This is done after placing everything but the format and version bits in the symbol.

Auxiliary files:
1. `qrref/custom_types.py`: Custom types for type hinting throughout the package.
2. `qrref/qr.py`: Assemble and visualize the QR code.
3. `qrref/settings.py`: Global settings. Currently only one, which is the encoding to use for byte strings (Latin-1 or UTF-8).
4. `qrref/table_data.py`: Data from tables, either in the form of dictionaries or functions.
