@isahaq/barcode
v2.0.0
Published
Universal barcode and QR code generator for Node.js and the browser: 40+ symbologies, PNG/SVG/HTML/PDF output, batch generation, logo and watermark support, validation, CLI and Express.js integration
Maintainers
Readme
Isahaq Barcode Generator
Barcode and QR code generation for Node.js and the browser. 45 symbologies, PNG / SVG / HTML / PDF output, a CLI, and a builder for QR codes with logos and watermarks.
Encoding is done by bwip-js (a port of the
BWIPP reference implementation), so every advertised type and output format
produces a real, scannable symbology. npm run verify:scan proves it by decoding
generated barcodes with ZXing.
Contents
- Installation
- Quick start
- Upgrading from 1.x
- Supported barcode types
- Output formats
- Render options
- QR codes with logos, labels and watermarks
- Validation
- Batch generation
- Express.js integration
- Browser usage
- CLI
- TypeScript
- API reference
- Development
Installation
npm install @isahaq/barcodeRequires Node.js 18 or newer.
canvas is an optional dependency. It is only needed for QR codes that
composite a logo, label or watermark. Everything else - all barcode types, all
output formats, plain QR codes - works without it, so installs never fail on a
missing native toolchain.
npm install canvas # only if you need QR logos/labels/watermarksQuick start
const fs = require('fs/promises');
const BarcodeGenerator = require('@isahaq/barcode');
// PNG (returns a Promise<Buffer>)
await fs.writeFile(
'code128.png',
await BarcodeGenerator.png('1234567890', 'code128')
);
// SVG - async or sync, whichever suits the call site
const svg = await BarcodeGenerator.svg('5901234123457', 'ean13');
const svgNow = BarcodeGenerator.svgSync('5901234123457', 'ean13');
// HTML fragment with an inline SVG
const html = BarcodeGenerator.htmlSync('1234567890', 'code128');
// PDF
await fs.writeFile(
'label.pdf',
await BarcodeGenerator.pdf('1234567890', 'code128', { fitToBarcode: true })
);
// 2D symbologies - size them in pixels
const qr = await BarcodeGenerator.png('https://example.com', 'qrcode', {
size: 400,
});
const dm = await BarcodeGenerator.svg('SHIPMENT-000123', 'datamatrix', {
size: 200,
});Upgrading from 1.x
Version 2 rewrote the rendering core. In 1.x only PNG output was a real barcode: SVG, HTML and PDF drew decorative bars from character codes, and unsupported types silently produced a Code 128. Fixing that required two API changes:
// 1.x - synchronous
const buffer = BarcodeGenerator.png('1234567890', 'code128');
const svg = BarcodeGenerator.svg('1234567890', 'code128');
const results = BarcodeGenerator.batch(items);
// 2.x - promises, with sync variants for the text formats
const buffer = await BarcodeGenerator.png('1234567890', 'code128');
const svg = BarcodeGenerator.svgSync('1234567890', 'code128'); // or await .svg(...)
const results = await BarcodeGenerator.batch(items);See the CHANGELOG for the full list, including the removal of the
jpg/jpeg render formats (they never worked) and the corrected EAN-8 / UPC-A
check digit validation.
Supported barcode types
45 types across six categories. BarcodeGenerator.getBarcodeTypeInfo(type)
returns the metadata for any of them.
| Category | Types |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Linear | code128, code128a, code128b, code128c, code128auto, code39, code39extended, code39checksum, code39auto, code93, code25, code25auto, code32, standard25, standard25checksum, interleaved25, interleaved25checksum, interleaved25auto, msi, msichecksum, msiauto |
| EAN / UPC | ean13, ean8, ean2, ean5, upca, upce, itf14 |
| Postal | postnet, planet, rms4cc, kix, imb |
| Specialized | codabar, code11, pharmacode, pharmacodetwotracks |
| 2D matrix | qrcode, datamatrix, aztec, pdf417, microqr, maxicode |
| Stacked | code16k, code49 |
BarcodeGenerator.getBarcodeTypes(); // all 45 ids
BarcodeGenerator.getBarcodeCategories(); // ['LINEAR', 'EAN_UPC', ...]
BarcodeGenerator.getBarcodeTypesByCategory('matrix_2d'); // ['qrcode', 'datamatrix', ...]
BarcodeGenerator.getBarcodeTypeInfo('ean13');
// {
// type: 'ean13', name: 'EAN-13', category: 'EAN_UPC', symbology: 'ean13',
// description: 'EAN-13 - European Article Number',
// minLength: 12, maxLength: 13, charset: 'Numeric'
// }Output formats
| Format | Method | Returns |
| ------ | ----------------------- | ---------------------------- |
| png | png() | Promise<Buffer> |
| svg | svg() / svgSync() | Promise<string> / string |
| html | html() / htmlSync() | Promise<string> / string |
| pdf | pdf() | Promise<Buffer> |
generate() takes the format as an argument:
const output = await BarcodeGenerator.generate('1234567890', 'code128', 'pdf', {
pageSize: 'A4',
});Render options
await BarcodeGenerator.png('1234567890', 'code128', {
width: 3, // module (narrow bar) width in px default 2
height: 140, // bar height in px, 1D only default 100
size: 400, // target size in px, 2D/stacked only
displayValue: true, // print the human readable text default true
fontSize: 24, // text size in px default 20
textAlign: 'center', // center | left | right | justify
textMargin: 2, // gap between bars and text in px
textColor: '#1d3557', // defaults to lineColor
lineColor: '#1d3557', // bar colour default #000000
background: '#f1faee', // background colour default #ffffff
margin: 24, // quiet zone in px, or use quietZone
marginTop: 10, // per-side overrides
quietZone: 10, // quiet zone in modules default 10
rotate: 'N', // N | R | L | I
});Quiet zone: when no margin is given, the quiet zone is quietZone modules
(10 by default) rather than a fixed pixel count. Most specifications require at
least 10 narrow modules of clear space, and scanners reject codes with less. Pass
margin in pixels when you need an exact figure, or margin: 0 for none.
2D symbologies keep their own aspect ratio: height does not apply, and
size is honoured by scaling the module size to the nearest whole number, so the
result lands close to - not exactly on - the requested pixel size.
PDF-only options: pageWidth, pageHeight, pageSize (for example 'A4'),
fitToBarcode (size the page to the barcode plus its margins) and title.
HTML-only options: id, className, includeStyles.
Anything the encoder itself understands can be passed straight through:
await BarcodeGenerator.png('1234567890', 'code128', {
bwipOptions: { alttext: 'custom caption' },
});QR codes with logos, labels and watermarks
qrCode() / modernQr() return a chainable builder. Plain codes need no extra
dependencies; a logo, label or watermark requires the optional canvas package.
const buffer = await BarcodeGenerator.qrCode('https://example.com', {
size: 400,
errorCorrectionLevel: 'H',
}).generate();
// Or with the builder API
const QrCodeBuilder = BarcodeGenerator.QrCodeBuilder;
await QrCodeBuilder.create()
.data('https://example.com')
.size(400)
.margin(12)
.errorCorrectionLevel('H')
.foregroundColor([29, 53, 87]) // RGB array or '#1d3557'
.backgroundColor('#ffffff')
.logoPath('./logo.png') // path, URL or data URI
.logoSize(20) // percent of the QR code
.label('Scan me!')
.watermark('DRAFT', 'center')
.saveToFile('qr.png');
// Other outputs
const svg = await BarcodeGenerator.modernQr({
data: 'x',
format: 'svg',
}).generate();
const uri = await BarcodeGenerator.modernQr({ data: 'x' }).getDataUri();Watermark positions: top-left, top-center, top-right, left-center,
center, right-center, bottom-left, bottom-center, bottom-right
(getWatermarkPositions()).
Keep logoSize at or below roughly 25%. A larger logo covers too many modules
for the error correction to recover, and the code stops scanning.
Validation
Validation runs automatically before generation, and is also available directly:
BarcodeGenerator.validate('5901234123457', 'ean13');
// { valid: true, data: '5901234123457', type: 'ean13', length: 13, charset: 'Numeric' }
BarcodeGenerator.validate('1234567890123', 'ean13');
// { valid: false, error: 'Invalid EAN-13 check digit (expected 8)' }
BarcodeGenerator.validate('123', 'ean13');
// { valid: false, error: 'Data too short. Minimum length: 12' }EAN-13, EAN-8, UPC-A and ITF-14 accept the code with or without its trailing check digit; when one is supplied it is verified.
Batch generation
Per-item failures are reported in the result rather than rejecting the batch:
const results = await BarcodeGenerator.batch([
{ data: '1234567890', type: 'code128', format: 'png' },
{
data: '5901234123457',
type: 'ean13',
format: 'svg',
options: { width: 3 },
},
{ data: 'nope', type: 'ean13', format: 'png' },
]);
// [
// { index: 0, success: true, result: <Buffer ...>, data: '1234567890', type: 'code128', format: 'png' },
// { index: 1, success: true, result: '<svg ...', data: '5901234123457', type: 'ean13', format: 'svg' },
// { index: 2, success: false, error: 'Invalid data for ean13: Data too short. Minimum length: 12', ... }
// ]Express.js integration
const express = require('express');
const BarcodeGenerator = require('@isahaq/barcode');
const app = express();
app.get('/barcode/:data', async (req, res) => {
const { type = 'code128', format = 'png' } = req.query;
try {
const result = await BarcodeGenerator.generate(
req.params.data,
type,
format
);
res.set(
'Content-Type',
BarcodeGenerator.getRenderFormatInfo(format).mimeType
);
res.send(result);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
// Inline SVG needs no await
app.get('/inline/:data', (req, res) => {
res.type('svg').send(BarcodeGenerator.svgSync(req.params.data, 'code128'));
});A complete server, including QR and batch endpoints, is in examples/express-server.js.
Browser usage
Bundlers resolve the package to the browser build automatically through the
browser field. It shares the encoder and type registry with the Node build, so
output is identical; PDF generation and file writing are Node-only.
import BarcodeGenerator from '@isahaq/barcode';
// Synchronous SVG - no DOM required
element.innerHTML = BarcodeGenerator.svg('1234567890', 'code128');
// Canvas rendering
BarcodeGenerator.toCanvas(
document.querySelector('canvas'),
'1234567890',
'code128'
);
const dataUrl = BarcodeGenerator.dataUrl('1234567890', 'code128');
const blob = await BarcodeGenerator.png('1234567890', 'code128'); // Blob, not Buffer
const qrDataUrl = await BarcodeGenerator.qrCode('https://example.com', {
size: 300,
});CLI
npx barcode-generate --help# Barcodes
barcode-generate barcode -d 1234567890 -t code128 -f png -o barcode.png
barcode-generate barcode -d 5901234123457 -t ean13 -f pdf -o label.pdf
barcode-generate barcode -d "https://example.com" -t qrcode -s 400 -o qr.png
barcode-generate barcode -d 1234567890 -f svg # writes SVG to stdout
barcode-generate barcode -d 1234567890 --no-text --width 3 --height 140 -o bars.png
# QR codes with extras
barcode-generate qr -d "https://example.com" -s 400 -e H --label "Scan me" -o qr.png
# Batch generation from a JSON file
barcode-generate batch -i examples/batch-example.json -o ./output
# Discovery and validation
barcode-generate types
barcode-generate types -c matrix_2d
barcode-generate formats
barcode-generate validate -d 5901234123457 -t ean13Data goes to stdout and diagnostics to stderr, so the CLI pipes cleanly. Without
-o, binary formats are printed as base64. Colour output honours NO_COLOR.
Sizing flags mirror the render options: -w/--width (module width in px),
-h/--height (bar height in px), -s/--size (2D target size in px),
-q/--quiet-zone (quiet zone in modules, default 10) and -m/--margin (quiet
zone in px, overrides --quiet-zone).
Install globally with npm install -g @isahaq/barcode to drop the npx prefix.
TypeScript
Type declarations ship with the package - no @types install needed.
import BarcodeGenerator = require('@isahaq/barcode');
// or, with esModuleInterop: import BarcodeGenerator from '@isahaq/barcode';
const options: BarcodeGenerator.RenderOptions = { width: 3, height: 140 };
const png: Buffer = await BarcodeGenerator.png(
'1234567890',
'code128',
options
);
const result = BarcodeGenerator.validate('5901234123457', 'ean13');
if (result.valid) {
console.log(result.charset); // narrowed to the success shape
}API reference
Generation
| Method | Returns |
| --------------------------------------- | --------------------------- |
| generate(data, type?, format?, opts?) | Promise<Buffer \| string> |
| png(data, type?, opts?) | Promise<Buffer> |
| svg(data, type?, opts?) | Promise<string> |
| svgSync(data, type?, opts?) | string |
| html(data, type?, opts?) | Promise<string> |
| htmlSync(data, type?, opts?) | string |
| pdf(data, type?, opts?) | Promise<Buffer> |
| batch(items) | Promise<BatchResult[]> |
| qrCode(data, opts?) | QrCodeBuilder |
| modernQr(opts?) | QrCodeBuilder |
type defaults to code128, format to png.
Metadata
| Method | Returns |
| -------------------------------- | -------------------------- |
| validate(data, type) | ValidationResult |
| getBarcodeTypes() | string[] |
| getBarcodeCategories() | string[] |
| getBarcodeTypesByCategory(cat) | string[] |
| getBarcodeTypeInfo(type) | BarcodeTypeInfo \| null |
| getRenderFormats() | string[] |
| getRenderFormatInfo(format) | RenderFormatInfo \| null |
| getWatermarkPositions() | string[] |
| getDefaultOptions() | RenderOptions |
Building blocks
Attached to the default export for advanced use: QrCodeBuilder,
BarcodeService, BarcodeEncoder, BarcodeTypes, RenderFormats, Validator.
const { BarcodeEncoder, BarcodeTypes } = require('@isahaq/barcode');
BarcodeEncoder.getDimensions('1234567890', 'code128', {
width: 2,
height: 100,
});
// { width: 220, height: 153 } bars + human readable text + quiet zone
BarcodeTypes.getSymbology('aztec'); // 'azteccode'Development
npm install
npm test # jest
npm run lint # eslint
npm run format # prettier --write
npm run typecheck # tsc against index.d.ts
npm run verify:scan # generate barcodes and decode them with ZXing
npm run build # lint + format:check + typecheck + test
node examples/basic-usage.js
npm run dev # express example on :3000License
MIT - see LICENSE.
