npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

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.

npm version License: MIT

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

npm install isahaq-barcode

Requires 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/watermarks

Quick 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 ean13

Data 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 :3000

License

MIT - see LICENSE.