Decoding/Encoding QR Code With Pure JavaScript

Category: Javascript | April 7, 2025
Authornuintun
Last UpdateApril 7, 2025
LicenseMIT
Tags
Views167 views
Decoding/Encoding QR Code With Pure JavaScript

QR code encoder and decoder tools that help you quickly generate QR codes from given contents and decode QR codes from images.

How to use it:

Install the package.

# Yarn
$ yarn add @nuintun/qrcode
# NPM
$ npm install @nuintun/qrcode --save

Import modules as per your needs.

// encoder
import { Alphanumeric, Byte, Encoder, Hanzi, Kanji, Numeric } from '@nuintun/qrcode';
// decoder
import { binarize, Decoder, Detector, grayscale } from '@nuintun/qrcode';

Encoder

Generate a QR code from the content you provide.

const encoder = new Encoder({
      hints?: { fnc1?: FNC1 };
      version?: 'Auto' | number;
      level?: 'L' | 'M' | 'Q' | 'H';
      encode?: (content: string, charset: Charset) => Uint8Array;
});
const qrcode = encoder.encode(
  // Hanzi
  new Hanzi('你好世界'),
  // Byte
  new Byte('\nhello world\n'),
  // Kanji
  new Kanji('こんにちは世界')
);
console.log(qrcode.toDataURL());

Encoder Interface:

export class Alphanumeric {
  public constructor(content: string);
}
export class Byte {
  public constructor(content: string, charset?: Charset);
}
export class Hanzi {
  public constructor(content: string);
}
export class Kanji {
  public constructor(content: string);
}
export class Numeric {
  public constructor(content: string);
}
export interface EncoderOptions {
  hints?: { fnc1?: FNC1 };
  version?: 'Auto' | number;
  level?: 'L' | 'M' | 'Q' | 'H';
  encode?: (content: string, charset: Charset) => Uint8Array;
}
declare interface DataURLOptions {
  margin?: number;
  foreground?: [R: number, G: number, B: number];
  background?: [R: number, G: number, B: number];
}
export class Encoded {
  public size: number;
  public mask: number;
  public level: string;
  public version: number;
  public get(x: number, y: number): number;
  public toDataURL(moduleSize: number, options?: DataURLOptions): string;
}
export class Encoder {
  public constructor(options?: EncoderOptions);
  public encode(...segments: (Alphanumeric | Byte | Hanzi | Kanji | Numeric)[]): Encoded;
}

Decoder:

Decode the QR code data from an image you provide.

const image = new Image();
image.crossOrigin = 'anonymous';
image.addEventListener('error', () => {
  console.error('image load error');
});
image.addEventListener('load', () => {
  const { width, height } = image;
  const canvas = new OffscreenCanvas(width, height);
  const context = canvas.getContext('2d')!;
  context.drawImage(image, 0, 0);
  const luminances = grayscale(context.getImageData(0, 0, width, height));
  const binarized = binarize(luminances, width, height);
  const detector = new Detector();
  const detected = detector.detect(binarized);
  const decoder = new Decoder();
  let current = detected.next();
  while (!current.done) {
    let succeed = false;
    const detect = current.value;
    try {
      const { size, finder, alignment } = detect;
      const decoded = decoder.decode(detect.matrix);
      // Finder
      const { topLeft, topRight, bottomLeft } = finder;
      // Corners
      const topLeftCorner = detect.mapping(0, 0);
      const topRightCorner = detect.mapping(size, 0);
      const bottomRightCorner = detect.mapping(size, size);
      const bottomLeftCorner = detect.mapping(0, size);
      // Timing
      const topLeftTiming = detect.mapping(6.5, 6.5);
      const topRightTiming = detect.mapping(size - 6.5, 6.5);
      const bottomLeftTiming = detect.mapping(6.5, size - 6.5);
      console.log({
        content: decoded.content,
        finder: [topLeft, topRight, bottomLeft],
        alignment: alignment ? alignment : null,
        timing: [topLeftTiming, topRightTiming, bottomLeftTiming],
        corners: [topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner]
      });
      succeed = true;
    } catch {
      // Decode failed, skipping...
    }
    // Notice: pass succeed to next() is very important,
    // This can significantly reduce the number of detections.
    current = detected.next(succeed);
  }
});
image.src = '/path/to/qrcode.jpg';

Decoder Interface:

export class BitMatrix {
  public constructor(width: number, height: number, bits?: Int32Array);
  public get width(): number;
  public get height(): number;
  public set(x: number, y: number): void;
  public get(x: number, y: number): number;
  public flip(): void;
  public flip(x: number, y: number): void;
  public clone(): BitMatrix;
  public setRegion(left: number, top: number, width: number, height: number): void;
}
export class Point {
  public get x(): number;
  public get y(): number;
}
export class Pattern extends Point {
  public get moduleSize(): number;
}
declare class FinderPatternGroup {
  public get topLeft(): Pattern;
  public get topRight(): Pattern;
  public get bottomLeft(): Pattern;
}
export class Detected {
  public get matrix(): BitMatrix;
  public get finder(): FinderPatternGroup;
  public get alignment(): Pattern | undefined;
  public get size(): number;
  public get moduleSize(): number;
  public mapping(x: number, y: number): Point;
}
declare interface Structured {
  readonly index: number;
  readonly count: number;
  readonly parity: number;
}
export class Decoded {
  public get mask(): number;
  public get level(): string;
  public get version(): number;
  public get mirror(): boolean;
  public get content(): string;
  public get corrected(): number;
  public get symbology(): string;
  public get fnc1(): FNC1 | false;
  public get codewords(): Uint8Array;
  public get structured(): Structured | false;
}
export function grayscale(imageData: ImageData): Uint8Array;
export function binarize(luminances: Uint8Array, width: number, height: number): BitMatrix;
export interface DetectorOptions {
  strict?: boolean;
}
export class Detector {
  public constructor(options?: DetectorOptions);
  public detect(binarized: BitMatrix): Generator<Detected, void, boolean>;
}
export interface DecoderOptions {
  decode?: (bytes: Uint8Array, charset: Charset) => string;
}
export class Decoder {
  public constructor(options?: DecoderOptions);
  public decode(matrix: BitMatrix): Decoded;
}

Changelog:

v5.0.2 (04/07/2025)

  • Update

You Might Be Interested In:


One thought on “Decoding/Encoding QR Code With Pure JavaScript

Leave a Reply