Decoding/Encoding QR Code With Pure JavaScript

Category: Javascript | April 7, 2025
Author:nuintun
Views Total:102 views
Official Page:Go to website
Last Update:April 7, 2025
License:MIT

Preview:

Decoding/Encoding QR Code With Pure JavaScript

Description:

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