NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
QR for Laravel

Low-level encoder

Encoder implements QR Code Model 2 (ISO/IEC 18004:2015) — framework-free and stateless apart from input-independent lookup tables, so it is safe in long-running workers. Use it directly for explicit segments:

use RoundlyConsulting\Qr\DataTransferObjects\EncodeOptions;
use RoundlyConsulting\Qr\Encoder\{Encoder, Segment};

$matrix = app(Encoder::class)->encode('data', new EncodeOptions(errorCorrection: ErrorCorrection::High));
$matrix = app(Encoder::class)->encodeSegments([Segment::alphanumeric('HELLO'), Segment::numeric('123')], new EncodeOptions);
Segment::totalBits([Segment::bytes('hi')], version: 1);   // ?int

The resolved options, with their defaults:

new EncodeOptions(                    // the encoder's resolved options (defaults shown)
    errorCorrection: ErrorCorrection::Medium, minVersion: 1, maxVersion: 40, mask: null,
    boostErrorCorrection: true, eci: EciMode::Auto, segmentation: Segmentation::Optimal, kanji: false,
);

How it encodes

  • Segmentation — Optimal (shortest mix of numeric, alphanumeric, byte and optional kanji segments), Single (the tightest single mode) or Byte.
  • Version — the smallest version in the allowed range whose capacity fits; otherwise DataTooLongException with the needed and available bits.
  • Boost — raises M → Q → H while the data still fits the chosen version; never changes the version, never lowers the level.
  • ECI 26 — auto emits it only when a byte segment carries non-ASCII UTF-8; when a designator is needed, kanji characters go into UTF-8 byte segments.
  • Masking — all eight masks scored with the ISO penalty rules (ties go to the lowest index), or a forced mask.
  • Segment::numeric(), alphanumeric(), bytes(), kanji() and eci() build explicit segments; a character outside a forced mode throws UnencodableCharacterException with its position.

Capacity (data codewords)

VersionLMQH
11916139
61361087660
13428334244180
402956233416661276

Version 13-M holds 331 bytes (EPC’s limit); version 40-L holds 7089 digits, 4296 alphanumeric characters or 2953 bytes.

QrMatrix

$matrix = Qr::matrix('HELLO WORLD');

$matrix->size();              // modules per side
$matrix->version();           // 1–40
$matrix->errorCorrection();   // ErrorCorrection
$matrix->mask();              // 0–7
$matrix->isDark($x, $y);      // bool
$matrix->row($y);             // one row
$matrix->rows();              // every row
$matrix->darkModuleCount();
$matrix->info();              // EncodingInfo
echo $matrix->toText();       // debug text, not an image format

EncodingInfo

$info = Qr::text('HELLO WORLD')->info();

$info->version;                  // chosen version
$info->errorCorrection;          // final level (after any boost)
$info->errorCorrectionBoosted;   // bool
$info->mask;                     // chosen mask
$info->segments;                 // list<SegmentInfo>: mode, characterCount, bitLength
$info->dataBits;                 // bits used
$info->capacityBits;             // bits available
$info->eciDesignator;            // ?int
$info->maskPenalties;            // 8 values when automatic, [] when forced

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.