Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Barcode Generator Laravel Package

picqer/php-barcode-generator

A lightweight PHP barcode generator supporting EAN, UPC, Code 128, Code 39, ITF and more. Output barcodes as SVG, PNG, JPG or HTML via a simple API. No external dependencies; works standalone or with Laravel.

Deep Wiki
Context7

Getting Started

composer require picqer/php-barcode-generator

There is nothing else to install: no service provider, no config file, no facade, no published assets. It is plain PHP, so the "integration" is whatever you write around it. The whole surface area is two decisions: which type constant you pass and which renderer you instantiate.

use Picqer\Barcode\BarcodeGeneratorSVG;

$generator = new BarcodeGeneratorSVG();
$svg = $generator->getBarcode('SKU-00123', $generator::TYPE_CODE_128, 2, 60);

The fastest first use case is an order/packing-slip label. A throwaway route gets you there in five minutes:

// routes/web.php
Route::get('/barcodes/{code}.svg', function (string $code) {
    $generator = new BarcodeGeneratorSVG();
    $svg = $generator->getBarcode($code, $generator::TYPE_CODE_128, 2, 60);

    return response($svg, 200, [
        'Content-Type'   => 'image/svg+xml',
        'Cache-Control'  => 'public, max-age=86400',
    ]);
})->where('code', '[A-Za-z0-9\-]+');

Where to look first, in this order:

  1. The README's table of supported types — it is the only real documentation, and the constant names are self-describing (TYPE_EAN_13, TYPE_CODE_128, TYPE_ITF_14, TYPE_CODABAR, TYPE_MSI, TYPE_PHARMA_CODE, …).
  2. The Exceptions/ directory — four or five classes that tell you exactly what can go wrong.
  3. The renderer classes — depending on your installed version you will use either the legacy BarcodeGeneratorSVG / BarcodeGeneratorPNG / BarcodeGeneratorHTML / BarcodeGeneratorJPG classes (2.x) or the Picqer\Barcode\Renderers\* namespace (3.x). Check the tag you actually pulled before copying a snippet from a blog post.

If you want this testable and swappable, bind a tiny wrapper in a service provider rather than new-ing renderers in controllers:

// app/Services/BarcodeService.php
class BarcodeService
{
    public function svg(string $code, string $type = BarcodeGeneratorSVG::TYPE_CODE_128, int $width = 2, int $height = 60): string
    {
        return (new BarcodeGeneratorSVG())->getBarcode($code, $type, $width, $height);
    }

    public function png(string $code, string $type = BarcodeGeneratorPNG::TYPE_CODE_128, int $width = 3, int $height = 80): string
    {
        return (new BarcodeGeneratorPNG())->getBarcode($code, $type, $width, $height);
    }
}

Implementation Patterns

Renderer → output → transport. Pick the renderer by destination, not by taste:

Destination Renderer Why
Blade / HTML page / email body BarcodeGeneratorSVG Crisp, small, no GD, styleable
PDF via dompdf BarcodeGeneratorPNG dompdf's SVG support is unreliable; rasterize at high width factor
PDF via Browsershot / wkhtmltopdf BarcodeGeneratorSVG Chromium renders it perfectly and stays sharp
Attachment / Storage::put BarcodeGeneratorPNG Bytes on disk, no markup
Interactive JS widget BarcodeGeneratorDynamicHTML Draws client-side; useless server-side

Single parameterised endpoint with a whitelist. One route serving PNG or SVG keeps caching and auth logic in one place, but never let the type come from raw user input — map it through a whitelist:

Route::get('/barcodes/{type}/{code}.{format}', BarcodeController::class)
    ->where('format', 'svg|png')
    ->where('code', '[A-Za-z0-9\-]+');

// BarcodeController
$types = [
    'ean13'   => BarcodeGeneratorPNG::TYPE_EAN_13,
    'code128' => BarcodeGeneratorPNG::TYPE_CODE_128,
    'itf14'   => BarcodeGeneratorPNG::TYPE_ITF_14,
];

abort_unless(array_key_exists($type, $types), 404);

Emails and PDFs. In a Mailable, inline it so clients do not block a remote image:

$png = app(BarcodeService::class)->png($order->reference);

$message->embedData($png, 'barcode.png', 'image/png');
// or, for a real attachment:
$this->attachData($png, "label-{$order->id}.png", ['mime' => 'image/png']);

Bulk labels belong in a job. Generating 500 PNGs inside a request will time out. Fan out a queued job per order, write to a disk, and only then build the merged PDF:

Storage::disk('labels')->put("{$order->id}.png", $png);

Cache aggressively — the output is deterministic. The bytes depend only on (type, code, widthFactor, height, colour), so key on exactly that:

$key = 'barcode:'.md5(serialize([$type, $code, $width, $height]));
$png = Cache::remember($key, now()->addWeek(), fn () => $service->png($code, $type, $width, $height));

For product catalogues this turns thousands of regenerations into a few dozen.

Type choice is a domain decision, not a style one. EAN-13/UPC-A for retail GTINs, Code128 for internal SKUs and serials (compact, full ASCII), Code39 only where a legacy scanner demands it (wide, uppercase-only unless you use the extended variant), ITF-14 for cartons, Codabar for library/medical workflows. Encode the choice in your model so nobody has to remember.

Testing. Assert on signatures and dimensions rather than pixel-diffs: SVG output starts with <svg, PNG starts with \x89PNG, and a known EAN-13 produces the expected width for a given width factor. Add a feature test that invalid input returns 422 rather than 500.

Gotchas and Tips

Catch the exceptions or your invoices will 500. InvalidCharacterException, InvalidLengthException, and UnknownTypeException all extend BarcodeException. Any code path that renders a barcode from database content can be handed a bad SKU, so wrap generation and convert to a validation error or a placeholder image:

try {
    $png = $service->png($product->sku);
} catch (BarcodeException $e) {
    report($e);
    abort(422, 'Invalid barcode value.');
}

Leading zeros and integer columns. An EAN-13 starting with 0 stored in an INT column silently becomes a 12-digit barcode. Store barcode values in CHAR/VARCHAR and cast to string before passing them in.

Length rules differ per symbology. EAN-13 accepts 12 digits (checksum appended for you) or 13 (must be valid); UPC-A accepts 11 or 12; EAN-8 accepts 7 or 8. If you generate the check digit yourself, verify it matches, or you will ship labels that scan to a different number than your database.

widthFactor is not pixels. It is the multiplier for the narrow bar module. Do not generate at default size and then stretch the <img> with CSS — resampling destroys the bar-width ratios and scanners reject it. Generate at the physical size you need. For 300 dpi print, width factor 3–4 and height 80–120 is a sane starting point.

The library does not add a quiet zone. White space either side of the symbol is mandatory for scanning and is absent from the SVG/PNG output. Add it yourself with padding in the container, or your warehouse scanners will be blamed for a bug in your CSS.

The human-readable text is on you. Most real labels want the number printed underneath. Render it in Blade/PDF below the barcode; the package will not do it.

PNG requires ext-gd. Add ext-gd to composer.json or your Dockerfile. SVG and HTML renderers need nothing.

The HTML renderer is heavy. It emits one <div> per module. A page of 100 product barcodes becomes tens of thousands of DOM nodes and a sluggish page. Use SVG for anything list-shaped; the HTML renderer is only reasonable for one-off inline snippets.

PNG background is transparent. Usually fine, but on dark email clients or when composited into a PDF it can look like a black box. If it matters, set a white background in the container or in your PDF template.

1D only. There is no QR or DataMatrix here. If you need a URL or GS1 Digital Link payload, pair it with a QR package (bacon/bacon-qr-code or simplesoftwareio/simple-qrcode) rather than forcing a 40-character string into Code128 on a 50 mm label — the width scales linearly with data length and it will not fit.

DynamicHtmlRenderer is a trap in emails and PDFs. It emits JavaScript; CSP headers will block it and dompdf will ignore it.

LGPL-3.0 in a commercial app. Using it as an unmodified Composer dependency from proprietary Laravel code is the intended use case. Do not copy its classes into app/ to "customise" them — that turns your fork into a derivative work you must publish. If you need different output, implement a renderer (3.x exposes a renderer interface) instead of editing one.

Version drift. If a tutorial's BarcodeGeneratorPNG::getBarcode(...) signature does not match your installed version, you are on 3.x and looking at 2.x docs. Pin the major version in composer.json and read the tags, not the blog posts.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console