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

Zend Barcode Laravel Package

zendframework/zend-barcode

Zend Barcode is a standalone PHP component from Zend Framework for generating barcodes. It supports common symbologies such as Code 39, Code 128, EAN, UPC, QR Code, and PDF417, with renderers for images and PDF, plus validation and object-oriented configuration.

Deep Wiki
Context7

Getting Started

Install (and read the abandoned warning first). zendframework/zend-barcode was archived when Zend Framework became Laminas; the last tag is 2.8.0 (2019-12-26) and Composer marks it abandoned. It still installs, but its composer.json pins php: ^5.6 || ^7.0, so on PHP 8.x you'll need --ignore-platform-req=php or you'll hit a resolution wall. For anything new, install the maintained fork and swap namespaces — the API is byte-for-byte identical:

composer require laminas/laminas-barcode   # Zend\Barcode\* -> Laminas\Barcode\*

You need the GD extension (ext-gd) for the image path; the PDF renderer additionally wants the long-dead zendframework/zendpdf, which is why most teams never use it.

Minimal path to a barcode. The whole component is two objects: an Object (the symbology) and a Renderer (the output format). Barcode::factory() wires them:

use Zend\Barcode\Barcode;

$renderer = Barcode::factory(
    'code128',                                  // Object
    'image',                                    // Renderer
    ['text' => 'ORD-2024-000123', 'drawText' => true, 'font' => public_path('fonts/DejaVuSans.ttf')],
    ['imageType' => 'png', 'width' => 400, 'height' => 120,
     'horizontalPosition' => 'center', 'verticalPosition' => 'middle']
);

$renderer->draw();                 // builds the GD resource
$gd = $renderer->getImage();       // GD resource
ob_start(); imagepng($gd); $png = ob_get_clean();

return response($png, 200, ['Content-Type' => 'image/png', 'Cache-Control' => 'public, max-age=31536000']);

Where to look first. src/Barcode.php for factory() and the type→class map; src/Object/* for the symbologies and their option setters (Code128, Ean13, QrCode, Pdf417, Itf14, …); src/Renderer/* for Image, Svg, Pdf, Html. The options array you pass to factory() is just sugar for the setters on those two classes — when an option name isn't obvious, read the class.

First use case. A packing-slip / order-lookup barcode: code128 with the order number, rendered to PNG in a route, <img>-ed into the slip. It's the cheapest thing to ship and immediately proves the pipeline.

Implementation Patterns

Wrap it in one service, not scattered factory() calls. Options are verbose and easy to drift; centralise them.

class BarcodeService
{
    public function png(string $type, string $text, array $options = []): string
    {
        $renderer = Barcode::factory($type, 'image',
            ['text' => $text, 'drawText' => true, 'font' => public_path('fonts/DejaVuSans.ttf')] + $options,
            ['imageType' => 'png', 'width' => 400, 'height' => 120] + $options
        );
        $renderer->draw();
        ob_start(); imagepng($renderer->getImage());
        return ob_get_clean();
    }
}

Cache the bytes, always. Output is deterministic for a given type + text + options, so key on sha1($type.$text.serialize($options)) and Cache::rememberForever(), or write to storage/app/barcodes/{hash}.png and serve from there. This matters most for QR/PDF417, which are CPU-heavy relative to the other symbologies.

SVG for anything printed, PNG for anything on screen. Barcode::factory('code128', 'svg', [...])->draw() returns the SVG as a string — vector, tiny, crisp at any DPI, ideal for invoices, labels and PDF embedding. Don't reach for the Pdf renderer just to get a barcode into a PDF; render SVG (or a 600px-wide PNG) and let your PDF library place it. It avoids dragging an abandoned dependency into the app.

Batch/label sheets: build the renderer once, swap the barcode. A loop of Barcode::factory() re-parses options every iteration; instead keep the renderer and call setBarcode(Barcode::makeBarcode('code128', ['text' => $next])). You can also pass an already-constructed Object or Renderer instance as the first/second argument to factory() instead of a string.

Validate at the domain boundary, not at the renderer. Each symbology is strict: Code39 rejects lowercase, EAN/UPC want digits of an exact length and append the check digit themselves. Put a small guard (regex/length per symbology) in a FormRequest or value object so the user sees "invalid barcode" rather than a stack trace. Catch Zend\Barcode\Exception\ExceptionInterface and log the message — it's usually precise about which character is illegal.

HTML renderer is a convenience for the "I just need an <img> tag" case (it wraps the GD output). In Laravel you'll almost always prefer returning your own Response/view over letting a renderer echo markup — use it only if you're porting existing ZF view code.

Gotchas and Tips

  • automaticRenderError is true by default. An invalid symbology/text silently produces a barcode image with the error message drawn in it — which looks like a working barcode until someone scans it in the warehouse. Always pass false as the fourth/fifth argument in production paths: Barcode::factory($type, $renderer, $opts, $rendererOpts, false).
  • render() writes headers and echoes. Calling it inside a Laravel controller after the response has started can emit "headers already sent" warnings and corrupts JSON responses. Use draw() + getImage() and return a real Response.
  • Default images are tiny. The image height follows the barcode's barHeight (≈50px) unless you set height on the renderer. Scaling a 50px-tall PNG inside HTML looks mushy — render at 2–3× (or use SVG) and constrain with CSS.
  • Quiet zones matter. withQuietZones defaults on; disabling it to save pixels is a common cause of "the scanner won't read it". Same for horizontalPosition — keep some white margin around the bars.
  • Don't append check digits yourself. Ean13 takes 12 digits and computes the 13th; feeding it 13 gives you a wrong or rejected code. Code39 has its own optional withChecksum.
  • drawText needs a real font. Without the font option you fall back to GD's built-in bitmap font, which is unreadable at label sizes. Ship a TTF in resources/fonts and reference it with public_path()/resource_path().
  • 2D is renderer-limited. QrCode and Pdf417 are drawn as bitmaps, so expect them to work with the image renderer only — the SVG path doesn't have a bar-by-bar representation of them. If you need vector QR, use a dedicated QR package (endroid/qr-code, bacon/bacon-qr-code).
  • Extension points are clean if you need them. Subclass Zend\Barcode\Object\AbstractObject (implement validateText, getCharacters, getChecksum, draw) for a proprietary symbology, or Renderer\AbstractRenderer for a bespoke output — then hand the instance to factory(). You generally cannot register a new string type without touching the internal map, so pass the object.
  • If the migration to Laminas isn't an option, at minimum pin the version, add ext-gd to composer.json, and put a test around the one or two symbologies you use — this code is frozen, and PHP runtime changes (GD defaults, PHP 8 type strictness) will surface as silent rendering differences, not exceptions.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings