Library / SDK
Bacon/BaconQrCode avatar
Bacon/BaconQrCode

BaconQrCode: PHP QR code generation from a partial ZXing port

QR Code Generator for PHP

2,111 stars231 forksPHPBSD-2-Clause

At a glance

What is it?
BaconQrCode is a PHP encoder for QR codes, ported from ZXing's encoder side only. It ships three vector and raster backends, and its Imagick backend carries a white-pixel defect traceable to a bug in ImageMagick's path rasterizer.
Who is it for?
BaconQrCode suits PHP projects that need to generate QR codes without decoding. SVG output works with XMLWriter, which most PHP installs include, and avoids the rasterization bugs in ImageMagick's fill path.
Can I use it commercially?
Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 26 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A partial port of ZXing: encoder only, with Reed Solomon swapped out

BaconQrCode is a PHP library for generating QR codes, built as a port of the QR code portion of the ZXing library. That heritage comes with a hard boundary: only the encoder is included. According to the README, the decoder portion could be added later, but as of v3.1.1, BaconQrCode writes QR codes and cannot read them. Any application that needs to parse or verify a QR code must look elsewhere.

Reed Solomon error correction is the other area where the port diverges from ZXing. ZXing's own codec for Reed Solomon performs quite slowly in PHP, so the project replaced it with the implementation by Phil Karn. This change is not visible to callers, since the Writer and renderer API remain the same regardless of which codec handles the error correction math underneath. In practice, BaconQrCode is not a byte-for-byte translation of the Java original: the error correction core was chosen for PHP runtime performance rather than parity with ZXing's architecture.

On Packagist, the package is listed as `bacon/bacon-qr-code` and carries the BSD-2-Clause licence. Version v3.1.1 and v3.1.0 arrived on 2026-04-05, with v3.0.4 on 2026-03-16, and the last repository push was on 2026-09-16.

Packagist as the install path, and extension requirements that differ by backend

On Packagist, the package is `bacon/bacon-qr-code`. The README does not give a Composer install command in its own prose, but the Packagist badge in the README links to the listing where the standard install line appears. Usage examples are what the README leads with rather than setup steps, so Packagist is the authoritative source for the install form.

Before running any code, the choice of rendering backend determines which PHP extension is required. `ImagickImageBackEnd` requires the Imagick PHP extension and the underlying ImageMagick native library. `SvgImageBackEnd` requires only XMLWriter, which ships with PHP in most standard distributions. `GDLibRenderer` requires the GD extension, also bundled with most PHP installs. SVG and GD output can therefore be used in environments where installing non-default extensions is restricted, while Imagick raster output cannot.

At the repository root, the project contains `composer.json`, `phpunit.xml.dist`, `phpcs.xml`, and a `CLAUDE.md` file alongside the standard `.gitignore` and `.gitattributes`. Source code lives under `src/` and tests under `test/`. A `CHANGELOG.md` at the top level tracks the release history.

Writer wraps a renderer, and ImageRenderer takes the backend as a separate argument

For three of the four backends, the API follows a three-layer construction: a backend object goes into an `ImageRenderer` alongside a `RendererStyle`, and that `ImageRenderer` goes into a `Writer`. `RendererStyle` receives the image size as its first argument, and the README examples pass `400`. `writeFile` takes the data string as its first argument and the output file path as its second.

php
use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer;

$renderer = new ImageRenderer(
    new RendererStyle(400),
    new ImagickImageBackEnd()
);
$writer = new Writer($renderer);
$writer->writeFile('Hello World!', 'qrcode.png');

Swapping `ImagickImageBackEnd` for `SvgImageBackEnd` or `EpsImageBackEnd` in this construction requires no other change to the Writer or file call. `GDLibRenderer` takes a different path: it replaces both `ImageRenderer` and the backend with a single class, described in its own section below. All four backends are otherwise driven through the same `Writer` interface, so `writeFile` works identically once a renderer is in place.

ImagickImageBackEnd produces white-pixel artifacts due to a bug in ImageMagick's path rasterizer

When `ImagickImageBackEnd` is in use, single white pixels may appear inside filled regions. The README states this is most visible when the margin is set to 0, where artifacts appear at the image edge, but they can appear at any position in the image.

The README attributes the cause to a bug in ImageMagick's path fill rasterizer, specifically in the `GetFillAlpha` function inside `MagickCore/draw.c`. Two defects combine: an off-by-one error in the winding number calculation, and an edge skipping bug in the scanline processing. Together these can incorrectly classify pixels as outside a polygon when they are inside.

Two workarounds are documented and rejected. Canvas padding, meaning rendering on a larger canvas and then cropping, does not work because the required padding depends on the scale factor, path complexity and ImageMagick's internal edge processing state, and no fixed padding value is safe for all inputs. Post-processing to scan for and remove isolated white pixels risks corrupting legitimate rendering features such as curved module edges. Because the defect originates in the upstream C library rather than in BaconQrCode's PHP code, the library cannot fix it on its own. The README's stated resolution is to use `SvgImageBackEnd` or `GDLibRenderer` instead when artifact-free output is necessary.

GDLibRenderer removes the Imagick dependency but loses gradient and curve support

GD support is intentionally excluded as a backend for `ImageRenderer`. Instead, the library provides `GDLibRenderer` as a separate renderer class, with two limitations stated explicitly in the README: it does not support gradient, and it does not support any curves, so the QR code always comes out with squared module corners regardless of any styling configuration.

php
use BaconQrCode\Renderer\GDLibRenderer;
use BaconQrCode\Writer;

$renderer = new GDLibRenderer(400);
$writer = new Writer($renderer);
$writer->writeFile('Hello World!', 'qrcode.png');

Here the constructor for `GDLibRenderer` takes the size directly rather than through a `RendererStyle`. GD avoids both the Imagick extension requirement and the white-pixel artifact, at the cost of style options. For output that only needs to be scannable with no decorative styling, `GDLibRenderer` is the lighter setup and the safer choice regarding artifacts. For output requiring gradient fills or round module corners, neither GD nor Imagick is suitable, and SVG is the only vector option remaining.

SvgImageBackEnd and EpsImageBackEnd produce vector output without passing through a raster path

Two of the three backends available under `ImageRenderer` write vector files. `SvgImageBackEnd` uses XMLWriter to produce SVG, and `EpsImageBackEnd` produces EPS. Neither goes through a raster layer, so the white-pixel defect in ImageMagick's fill rasterizer does not affect either of them.

SVG has practical advantages for web use. An SVG file scales to any display size without quality loss, can be embedded directly in HTML, and renders in any current browser without additional software. EPS targets print workflows and requires a PostScript-compatible renderer or conversion step to view outside a typesetting toolchain. Neither backend has documented size or styling parameters beyond what `RendererStyle` provides, so the size argument in `RendererStyle` applies even when the output is vector.

Choosing `SvgImageBackEnd` also removes the Imagick dependency entirely. XMLWriter ships with most PHP builds as part of the standard extension set, adding no new install requirement on a typical shared host or container image. For a web application that only needs a QR code image in the HTTP response, `SvgImageBackEnd` is the shorter construction, avoids the known artifact defect, and works with what most PHP environments already provide.

v3.1.1, BSD-2-Clause, and a test suite that requires Node.js alongside PHP

Version v3.1.1 and v3.1.0 both arrived on 2026-04-05, with v3.0.4 on 2026-03-16. The repository is not archived, and the last push was on 2026-09-16.

BSD-2-Clause is the licence in both the Packagist metadata and the LICENSE file at the repository root. BSD-2-Clause requires attribution and prohibits using the project name in endorsements; it imposes no further restrictions on use, modification or redistribution. This article does not offer legal advice on how those terms apply to any specific situation.

A cross-language dependency makes the development setup unusual. Running the unit tests requires Node.js and the `pixelmatch` library. The README directs contributors to run `npm install`, and `package.json` at the repository root lists `pixelmatch` at `^7.1.0` as a dev dependency. That `package.json` marks the package as private, so it is not intended for publication to npm. Pixelmatch handles pixel-level comparison of rendered output in the test suite. Any developer working on the PHP encoder or renderer code still needs a working Node.js install to execute the full test suite, since phpunit alone does not cover the rendering assertions.

For a project adopting BaconQrCode as a library dependency, this Node.js requirement has no effect in production; it matters only to contributors who want to run all tests locally.

Editorial conclusion

BaconQrCode suits PHP projects that need to generate QR codes without decoding. SVG output works with XMLWriter, which most PHP installs include, and avoids the rasterization bugs in ImageMagick's fill path. GDLibRenderer is self-contained but produces only squared output with no gradient. Skip it when you need to scan or parse QR codes, since the library includes no decoder. Before adopting it, confirm your deployment provides the Imagick, GD or XMLWriter extension you plan to use, then run writeFile against your actual data strings, because the README does not document QR code capacity limits or error correction options.

Frequently asked questions

How do I install BaconQrCode in a PHP project?

The package is published on Packagist as `bacon/bacon-qr-code`. Add it through Composer. The README's Packagist badge links to the listing where the install command appears.

Does BaconQrCode support QR code decoding?

No. The README states BaconQrCode is a port of only the encoder portion of ZXing. The decoder is not included, though the README notes it could be added later.

What causes the white pixel artifacts in BaconQrCode's Imagick output?

The README attributes the defect to a bug in ImageMagick's path fill rasterizer in `GetFillAlpha` inside `MagickCore/draw.c`, combining an off-by-one error in the winding number calculation with an edge skipping bug in scanline processing. The recommended fix is to switch to `SvgImageBackEnd` or `GDLibRenderer`.

Does BaconQrCode require ImageMagick?

Only `ImagickImageBackEnd` requires ImageMagick and the Imagick PHP extension. `SvgImageBackEnd` uses only XMLWriter, and `GDLibRenderer` uses only the GD extension. Both alternatives are available in most standard PHP installs.

What licence does BaconQrCode use?

The project is distributed under the BSD-2-Clause licence, as listed in both the Packagist metadata and the LICENSE file at the repository root.

Official sources

  1. Bacon/BaconQrCode on GitHub
  2. Issues
  3. License: BSD-2-Clause
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bacon-baconqrcode.svg)](https://hysenlabs.com/projects/bacon-baconqrcode)