bacon/bacon-qr-code
PHP QR code generator (ZXing encoder port) with multiple renderers/back ends: Imagick, SVG, EPS, and a separate GDLib renderer. Generate QR codes to files or output with customizable size/style via Renderer and Writer APIs.
Installation:
composer require bacon/bacon-qr-code
Basic Usage (Imagick backend):
use BaconQrCode\Writer;
use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
$writer = new Writer(new ImageRenderer(400, new ImagickImageBackEnd()));
$writer->writeFile('Hello World!', 'qrcode.png');
GD Alternative (if Imagick unavailable):
use BaconQrCode\Renderer\GDLibRenderer;
$writer = new Writer(new GDLibRenderer(400));
$writer->writeFile('Hello World!', 'qrcode.png');
Generate a QR code for a product page URL and embed it in a Blade view:
// In a controller
public function showProduct($id) {
$qr = new Writer(new ImageRenderer(300, new ImagickImageBackEnd()));
$qr->writeFile(route('product.show', $id), storage_path('app/qr_'.$id.'.png'));
return view('product.show', ['qr_path' => 'qr_'.$id.'.png']);
}
// In Blade
<img src="{{ asset('storage/qr_'.$product->id.'.png') }}" alt="QR Code">
Dynamic QR Generation
// Generate QR for user-specific data
$userData = ['id' => $user->id, 'email' => $user->email];
$qrData = json_encode($userData);
$writer->writeFile($qrData, "user_{$user->id}.png");
Custom Styling
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Renderer\Color\Rgb;
$style = new RendererStyle(400);
$style->setForegroundColor(new Rgb(0, 102, 204)); // Blue
$style->setBackgroundColor(new Rgb(255, 255, 255)); // White
$style->setMargin(2);
$renderer = new ImageRenderer($style, new ImagickImageBackEnd());
SVG Output for Scalability
use BaconQrCode\Renderer\Image\SvgImageBackEnd;
$writer = new Writer(new ImageRenderer(500, new SvgImageBackEnd()));
$writer->writeFile('https://example.com', 'qr.svg');
Batch Processing
$urls = ['url1', 'url2', 'url3'];
foreach ($urls as $index => $url) {
$writer->writeFile($url, "batch_{$index}.png");
}
Service Provider Pattern
// app/Providers/QrCodeServiceProvider.php
public function register() {
$this->app->singleton('qr.writer', function() {
return new Writer(new ImageRenderer(
new RendererStyle(400),
new ImagickImageBackEnd()
));
});
}
Middleware for QR Generation
// Generate QR for all authenticated users
public function handle($request, Closure $next) {
if (auth()->check()) {
$writer = app('qr.writer');
$writer->writeFile(route('user.profile', auth()->id()),
storage_path("app/qr_{auth()->id()}.png"));
}
return $next($request);
}
API Endpoint
Route::get('/qr/{data}', function($data) {
$writer = new Writer(new GDLibRenderer(300));
$path = temp_path('qr_'.md5($data).'.png');
$writer->writeFile($data, $path);
return response()->file($path)->deleteFileAfterSend(true);
});
Caching Strategy
public function getQrCode($data) {
$cacheKey = 'qr_'.md5($data);
return Cache::remember($cacheKey, now()->addHours(1), function() use ($data) {
$writer = app('qr.writer');
$path = storage_path("app/{$cacheKey}.png");
$writer->writeFile($data, $path);
return $path;
});
}
Imagick Artifacts
ImagickImageBackEnd (especially with margin=0).SvgImageBackEnd or GDLibRenderer for artifact-free output.
// Fallback to SVG if artifacts are critical
$backend = extension_loaded('imagick') ? new ImagickImageBackEnd() : new SvgImageBackEnd();
GD Limitations
GDLibRenderer produces square QR codes and lacks gradients.Memory Limits
SvgImageBackEnd for scalable vector output or optimize size:
$style = new RendererStyle(300); // Smaller size
Extension Dependencies
xmlwriter for SVG output or imagick for raster images.if (!extension_loaded('xmlwriter')) {
throw new \RuntimeException('xmlwriter extension required for SVG output');
}
Validate QR Codes Use online validators (e.g., QR Code Generator) to verify output.
Log Errors Wrap generation in try-catch:
try {
$writer->writeFile($data, $path);
} catch (\Exception $e) {
Log::error("QR Generation failed: {$e->getMessage()}");
throw $e;
}
Size Calculation
Use BaconQrCode\Writer::getSize() to estimate dimensions before generation:
$size = $writer->getSize($data);
$style = new RendererStyle($size);
Reuse Writers Instantiate writers once (e.g., in a service container) rather than per-request.
Cache Renderers
$renderer = new ImageRenderer(
new RendererStyle(400),
new ImagickImageBackEnd()
);
Cache::remember('qr.renderer', now()->addDays(7), function() use ($renderer) {
return $renderer;
});
Async Generation Use queues for non-critical QR codes:
Queue::push(new GenerateQrJob($data, $path));
Custom Eyes
use BaconQrCode\Renderer\RendererStyle\Eye\SimpleCircleEye;
$style = new RendererStyle(400);
$style->setEye(new SimpleCircleEye());
Gradient Backgrounds
use BaconQrCode\Renderer\Color\Rgb;
use BaconQrCode\Renderer\RendererStyle\Gradient\LinearGradient;
$style = new RendererStyle(400);
$style->setBackgroundGradient(
new LinearGradient(
new Rgb(255, 0, 0),
new Rgb(0, 0, 255)
)
);
Transparent PNGs
$style = new RendererStyle(400);
$style->setBackgroundColor(new Rgb(0, 0, 0, 0)); // RGBA with alpha=0
PHP Version
GDLibRenderer for older versions.Imagick Antialiasing Enable for smoother edges (v3.1.0+):
$backend = new ImagickImageBackEnd();
$backend->setAntialias(true);
UTF-8 Handling Ensure input strings are UTF-8 encoded:
$data = mb_convert_encoding($data, 'UTF-8');
Error Handling
Check for BaconQrCode\Exception\WriterException when generation fails.
How can I help you explore Laravel packages today?