Custom Renderers
The payload builder has no dependency on the image layer, so swapping the drawing is clean.
The Contract
php
namespace RealRashid\RaastQr\Renderers;
interface Renderer
{
public function png(string $payload, array $options = []): string;
public function svg(string $payload, array $options = []): string;
}Two methods. png() returns raw bytes, svg() returns a document string.
Binding Your Own
php
// app/Providers/AppServiceProvider.php
use RealRashid\RaastQr\Renderers\Renderer;
use App\Support\BaconRenderer;
public function register(): void
{
$this->app->bind(Renderer::class, BaconRenderer::class);
}Everything else — the builder, the facade, the Blade component, the Artisan commands — keeps working unchanged.
The Options Array
Whatever you accept is up to you, but honouring these keeps your renderer a drop-in replacement:
| Key | Type | Meaning |
|---|---|---|
size | int | Edge length in pixels |
margin | int | Quiet zone in modules |
error_correction | string | L, M, Q or H |
foreground | string|array | Dark module colour |
background | string|array | Background colour |
logo | array | ['path' => …, 'size' => …, 'punchout' => bool] |
label | array | ['text' => …, 'size' => …, 'font' => …] |
Example: Simple QrCode
php
namespace App\Support;
use RealRashid\RaastQr\Renderers\Renderer;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
class SimpleQrCodeRenderer implements Renderer
{
public function png(string $payload, array $options = []): string
{
return (string) $this->base($options)->format('png')->generate($payload);
}
public function svg(string $payload, array $options = []): string
{
return (string) $this->base($options)->format('svg')->generate($payload);
}
protected function base(array $options)
{
[$r, $g, $b] = $this->rgb($options['foreground'] ?? '#000000');
return QrCode::size($options['size'] ?? 900)
->margin($options['margin'] ?? 4)
->errorCorrection($options['error_correction'] ?? 'H')
->color($r, $g, $b);
}
protected function rgb(string $hex): array
{
$hex = ltrim($hex, '#');
return [
(int) hexdec(substr($hex, 0, 2)),
(int) hexdec(substr($hex, 2, 2)),
(int) hexdec(substr($hex, 4, 2)),
];
}
}Throwing Properly
Wrap failures in the package's own exception so callers can handle them uniformly:
php
use RealRashid\RaastQr\Exceptions\RaastQrException;
try {
return $this->draw($payload, $options);
} catch (\Throwable $e) {
throw RaastQrException::rendererFailure(
'Could not render the QR code: ' . $e->getMessage()
);
}See Handling Errors.
Faking It in Tests
A no-op renderer keeps image generation out of tests that don't care about pixels:
php
use RealRashid\RaastQr\Renderers\Renderer;
class FakeRenderer implements Renderer
{
public function png(string $payload, array $options = []): string
{
return 'png:' . $payload;
}
public function svg(string $payload, array $options = []): string
{
return '<svg data-payload="' . $payload . '"></svg>';
}
}php
$this->app->bind(Renderer::class, FakeRenderer::class);
expect(RaastQr::iban($iban)->toSvg())->toContain('0002020102110202000424');Fast, and it asserts the thing that actually matters — the payload.
Made with ❤️ from Pakistan