bacon/bacon-qr-code
BaconQrCode is a pure-PHP QR code generator ported from ZXing's encoder. It renders QR codes to PNG, SVG, EPS or GD images with customizable size, margin, colors, gradients and eye styles, backed by a fast Reed-Solomon codec for quick output. Encoder only.
Architecture fit
Renderer strategy. ImageRenderer + a backend (Imagick, Svg, Eps) or the standalone GDLibRenderer are the only decisions a consumer makes. This is the natural seam for us to wrap.QrCodeService bound as a singleton, a config/qr.php for defaults (size, margin, ECC level, foreground/background, disk), and a value object for style.Integration feasibility
composer require bacon/bacon-qr-code (v3.x requires PHP >= 8.1, which is comfortably inside Laravel 10/11/12 baselines). No publish step, no migrations, no bootstrapping.SvgImageBackEnd → ext-xmlwriter (bundled by default in most PHP builds) — lowest risk.GDLibRenderer → ext-gd (near-universal; enabled on Laravel Vapor by default).ImagickImageBackEnd → ext-imagick (frequently absent; requires a Dockerfile/layer change on Vapor or container hosts).Storage::disk()->put(), response()->streamDownload(), queued jobs, and mail attachments.Technical risk
GetFillAlpha rasterizer bug. The maintainers explicitly state it cannot be worked around in-library and recommend SVG or GD instead. This is a correctness risk for any code that must scan reliably at small physical sizes — treat it as a do-not-use backend unless an artifact workaround is proven on our target ImageMagick version.xmlwriter and gives us a vector asset we must rasterize downstream if a PNG is demanded.Dependents: 0, overall score 3.3) look like an indexing artifact rather than reality — this package is a well-known engine behind higher-level QR wrappers. Validate before treating the score as a proxy for adoption; a 3.3 with a complete changelog, CI badge, codecov, and a 3.1.1 patch release does not square with "0 dependents."sprintf('%.3F') in SVG transforms, issue #100) — resolved, but indicative that float formatting under non-C locales has historically been a source of subtle breakage in this codebase. Worth a regression test on our side if we run de_DE/fr_FR locales.Key questions
<img>, printed label, email, or downloadable asset? This single answer selects the backend and kills half the risk list.ext-imagick present in all target environments (local, CI, staging, production, any queue workers)? If not, is it worth adding for aesthetics alone?Stack fit
config/qr.php — default disk, size, margin, ECC level, backend, colors.App\Support\Qr\QrCodeGenerator — builds RendererStyle + backend from config, exposes svg(string $payload): string, png(string $payload): string, store(string $payload, string $path, string $disk): void.QrCode value object on models (->qrSvg()) for ergonomics.Migration path
simplesoftwareio/simple-qrcode: that package is a thin convenience layer whose v4 line delegates to this library. Dropping to bacon/bacon-qr-code directly removes an intermediary, gains explicit control over RendererStyle, and gets us on the actively maintained 3.x line — at the cost of rewriting call sites (QrCode::size(300)->generate(...) → our adapter). Contained change if call sites are few.endroid/qr-code: verify its current encoder dependency chain before assuming equivalence; the migration is API-shaped rather than engine-shaped and should be scoped as a rewrite of the QR service, not a version bump.Compatibility
xmlwriter (probably fine), gd (probably fine), imagick (assume absent until proven).Sequencing
ext-imagick end-to-end or commit to SVG/GD. Record the choice in the config default so it is not re-litigated.Storage/CDN.Maintenance
composer.lock; the realistic failure mode is slow response to a new CVE or PHP version, not abandonment mid-quarter. Have a fallback noted (swap to a fork or pin the last good tag).Support
RendererStyle, Eye, and Color options are discoverable only by reading source or IDE completion. Expect one "how do I do rounded corners?" question per new engineer — solve it once with an internal README snippet, not per-incident.qr.backend to svg").Scaling
size in config and prefer SVG for anything above ~800px.Failure modes
| Mode | Trigger | Impact | Mitigation |
|---|---|---|---|
| Missing PHP extension | imagick/gd/xmlwriter absent in a new container or Vapor build |
Hard failure at render time | Fail fast at boot (health check / config validation), document in Dockerfile, default to SVG |
| Imagick white-pixel artifacts | Any Imagick raster render | Codes that scan poorly at small print sizes or low margin | Default to SVG/GD; test-scan output in CI |
| Payload too large | Long URL with large query string, exceeds QR capacity for chosen ECC | Encoder exception, broken UX | Catch, validate length pre-encode, shorten URL/token instead of embedding raw data |
| Style feature unavailable | Gradient/curves requested on GD backend | Silent visual downgrade or exception | Config guard: validate style vs. backend at boot |
| Output write failure | Disk permissions, S3 credentials, disk full | Missing assets downstream | Queue + retry with backoff; surface to monitoring |
| Locale float formatting | Non-C locale server with SVG/EPS transforms | Malformed SVG/EPS geometry | Regression test; set LC_NUMERIC=C or verify #100 fix holds on our version |
| Major-version surprise | Caret bump picks up a 4.x with renderer API changes | Broken adapter | Pin ^3.1, upgrade deliberately with the golden-file tests |
Ramp-up
composer require, ~30 lines of adapter, done. The API is genuinely two classes deep.RendererStyle/Eye/Color/gradient configuration is undocumented and must be learned from src/. Budget a short internal write-up with copy-paste examples for the 3–4 styles we actually ship.How can I help you explore Laravel packages today?