QR Code Support
[!NOTE] The repository contains a bundled QR implementation under
QRCode/. Its source defines encoding through raster output, but application registration, deployment reachability, and successful execution are not established.QRCode/index.phpis a source-local wrapper: it includesqrlib.php, decodes GETqwithbase64_decodeandjson_decode, and passes$q->urlto QRcode::png. Treat it as an example wrapper, not a proven HTTP API.
Source-defined flow
flowchart TD
input[QRinput segments] --> bits[QRinputItem bitstreams]
bits --> version[QRspec minimum version selection]
version --> bytes[QRbitstream bytes]
bytes --> spec[QRspec block specification]
spec --> raw[QRrawcode blocks]
raw --> ecc[Reed-Solomon correction]
ecc --> frame[QRcode encodeMask frame]
frame --> mask[QRmask selection]
mask --> masked[Masked QR frame]
masked --> binary[QRtools binarize]
binary --> png[QRimage PNG]
masked --> jpg[QRimage JPEG]
Component responsibilities
[
{
"title": "Input validation and mode encoding",
"body": "In `QRCode/qrinput.php`, **QRinput** defaults to version `0` and **QR_ECLEVEL_L`. Its constructor throws when the version is below `0`, above `QRSPEC_VERSION_MAX`, or the correction level is above `QR_ECLEVEL_H`. **QRinputItem::encodeBitStream** uses **QRspec::maximumWords** to split oversized entries recursively. Entries are dispatched to the NUM, AN, 8-bit, KANJI, or STRUCTURE encoder and return the bitstream size, or `-1` on failure."
},
{
"title": "Bitstream assembly and version selection",
"body": "In `QRCode/qrbitstream.php`, **QRbitstream::toByte** converts stored bits into big-endian bytes, including a final partial byte; an empty stream produces an empty array. **QRinput::convertData** rebuilds the stream while adjusting the version until the data fits. A bitstream failure returns `-1`; if no version fits, the source throws `WRONG VERSION`. In `QRCode/qrspec.php`, **QRspec::getMinimumVersion** scans the capacity table from version 1 through the configured maximum and returns the first fitting version, or `-1`; the table contains versions 1 through 40."
},
{
"title": "Raw blocks and Reed–Solomon correction",
"body": "In `QRCode/qrencode.php`, **QRrawcode** obtains the input byte stream, reads the version and correction-level block specification from **QRspec**, allocates data and ECC lengths, initializes Reed–Solomon blocks through **QRrs::init_rs**, and creates **QRrsblock** instances for the block groups. In `QRCode/qrrscode.php`, **QRrs::init_rs** reuses a matching cached control block or delegates to **QRrsItem::init_rs_char** and stores the result. **QRrsItem::encode_rs_char** initializes parity symbols and iterates over data symbols using Galois-field lookup tables and the generator polynomial."
},
{
"title": "Frame filling and mask selection",
"body": "In `QRCode/qrencode.php`, **QRcode::encodeMask** validates the input, constructs **QRrawcode**, creates a version frame through **QRspec::newFrame**, and uses **FrameFiller** to interleave data and ECC bytes into the frame. It then adds remainder bits and either calls **QRmask::mask** for best-mask selection or **QRmask::makeMask** for the configured or explicitly supplied mask. The resulting version, width, and masked data are stored on the **QRcode** object. A null filler returns `NULL`."
},
{
"title": "Mask scoring",
"body": "In `QRCode/qrmask.php`, **QRmask::mask** evaluates the candidates in `checked_masks`, combines the black-module balance penalty with **QRmask::evaluateSymbol** demerits, and retains the candidate with the lowest demerit. The declared **QR_FIND_FROM_RANDOM** setting is false, so the source-defined best-mask configuration considers all eight mask numbers."
},
{
"title": "Frame caching and configuration",
"body": "In `QRCode/qrspec.php`, **QRspec::newFrame** rejects versions outside `1..QRSPEC_VERSION_MAX`. With caching enabled, frame cache lookup and writes use **QR_CACHE_DIR**. `QRCode/qrconfig.php` declares **QR_CACHEABLE** as `true`, places **QR_CACHE_DIR** under the `QRCode` directory, places **QR_LOG_DIR** under that same directory, enables **QR_FIND_BEST_MASK**, disables **QR_FIND_FROM_RANDOM**, sets **QR_DEFAULT_MASK** to `2` when best-mask selection is disabled, and sets **QR_PNG_MAXIMUM_SIZE** to `1024`."
},
{
"title": "Raster image construction",
"body": "In `QRCode/qrimage.php`, **QRimage::image** creates a white-and-black GD image, marks frame cells whose value is `'1'`, applies the outer frame margin, scales the result by `pixelPerPoint`, destroys the intermediate image, and returns the scaled image resource. **QRimage::png** emits PNG data to the response when the filename is false, writes to a filename when supplied, and writes both a file and response only when a filename is supplied and `saveandprint` is true. **QRimage::jpg** behaves similarly for JPEG output and applies the requested quality."
}
]
Output paths
| Output path | Source entry | Source-defined result | External effect |
|---|---|---|---|
| Binarized return | QRencode::encode with outfile set to false |
Returns QRtools::binarize output |
None declared in this branch |
| Text file | QRencode::encode with an outfile |
Writes newline-joined QRtools::binarize output |
Writes to the caller-selected filename |
| PNG | QRencode::encodePNG and QRimage::png | Uses a size bounded by QR_PNG_MAXIMUM_SIZE and emits PNG data or writes a PNG file | Response output when no filename is supplied; file output when a filename is supplied; both only when a filename is supplied and saveandprint is true |
| JPEG | QRimage::jpg | Emits JPEG data with the requested quality or writes a JPEG file | Response output or file output |
Constraints and unresolved behavior
[!WARNING] The
QRCode/index.phpwrapper uses the decodedq->urlvalue without source-proven validation, so it is not a stable machine-facing contract. The 8-bit convenience path inQRCode/qrencode.phpis unresolved: QRcode::encodeString8bit testsstringrather than$stringand calls QRinput::append with four arguments although the declared signature accepts mode, size, and data. The QRcode::png wrapper also assigns$saveandprint=falsewhen calling encodePNG, so forwarding a caller-supplied save-and-print value is not proven.Frame and mask caching may write beneath QR_CACHE_DIR, and text, PNG, and JPEG paths may write to caller-selected filenames. Image rendering depends on GD-style image functions. No evidence establishes writable directories, GD availability, successful execution, or an explicit success/error response; QRencode::encodePNG logs captured output and exception messages through QRtools::log instead of exposing an explicit result in its inspected body.
Updated