Skip to content

Reading and decoding

The reader accepts pixels, not a browser element. Give it an object with RGBA bytes, width and height, and it will locate, validate and decode supported symbols. That keeps the API usable with a canvas, an OffscreenCanvas, a Worker, Node.js image tooling or a test fixture.

The general reader

decode(image: ImageLike, options?: DecodeOptions): DecodeResult[]
decodeStrict(image: ImageLike, options?: object): DecodeResult

decode() returns every validated result it can find for the requested image. An empty array means “nothing valid in this frame”; it is not an exceptional condition and is exactly what a camera loop should expect.

The input shape is:

type ImageLike = {
  data: Uint8ClampedArray | Uint8Array | number[];
  width: number;
  height: number;
};

data is RGBA, four values per pixel, in row-major order. A browser can pass the result of ctx.getImageData(0, 0, width, height) directly. Transparent pixels are treated as white by the luminance conversion, which prevents a transparent quiet zone from turning into artificial black ink.

Decoder options

Option Meaning
formats Restrict the scan to format ids such as ['qr', 'pdf417']. Omitting it allows the normal supported-format search.
tryHarder Enables the additional retry work used by the reader. It defaults to true in the root API.
binarizer Selects 'global', 'hybrid' or 'auto' thresholding.
profile Set to 'camera' for stricter camera-oriented validation.
frameqr Passes profile-specific options to the Sythos Canvas QR detector.

Narrow the formats list when the application knows what it is looking for. That reduces work and avoids interpreting a specialised symbol through an unwanted format path.

A complete image round trip

import {
  decode,
  encode,
  toImageData,
} from '@sythos/js_barcode_universal';

const expected = 'read me once';
const generated = encode(expected, { format: 'qr', ecc: 'Q' });
const image = toImageData(generated, { scale: 6, margin: 4 });

const hits = decode(image, {
  formats: ['qr'],
  binarizer: 'auto',
  tryHarder: true,
});

if (hits.length === 0) {
  throw new Error('No validated QR Code was found');
}

console.log(hits[0].format, hits[0].text);
// qr read me once

The same call works with an actual camera frame after the application has copied it into the ImageLike shape. The SDK does not request camera access, draw video frames or manage permissions; those are platform responsibilities.

Result shape

Every result has the required fields text and format. Other fields are optional because different symbologies expose different evidence:

Field Present for or useful with
bytes Byte-oriented payloads.
segments PDF417-family compaction segments, in source order.
version, ecc QR-family metadata.
layers, compact, corrections Aztec metadata and Reed–Solomon work.
rows, columns, eccLevel, rowHeight PDF417-family geometry and correction metadata.
variant, eccCodewords MicroPDF417 variant metadata.
profile, certified, canvas Sythos Canvas QR profile metadata. certified is false for this project profile.
addon An attached EAN-2 or EAN-5 supplement.
confidence, bounds, rotation, quality Camera-profile evidence when the detector exposes it.
gs1, symbologyIdentifier, elements, gs1ParseError, gtin, linkage GS1 classification and parsed fields.

Treat all decoded text and parsed fields as untrusted input. The reader proves that a symbol is structurally valid; it does not decide whether the payload is safe for a business action.

Strict mode belongs at controlled boundaries

decodeStrict() throws instead of returning an empty result:

import {
  ChecksumError,
  FormatError,
  NotFoundError,
  decodeStrict,
} from '@sythos/js_barcode_universal';

try {
  const result = decodeStrict(image, { formats: ['datamatrix'] });
  console.log(result.text);
} catch (error) {
  if (error instanceof NotFoundError ||
      error instanceof FormatError ||
      error instanceof ChecksumError) {
    console.log('The image did not contain a validated Data Matrix');
  } else {
    throw error;
  }
}

For repeated frames, use decode() instead. Throwing for every empty frame turns an ordinary camera condition into noisy application control flow.

Camera profile

The optional camera profile asks for stricter validation of camera-oriented reads:

function readCameraFrame(frame) {
  const hits = decode(frame, {
    profile: 'camera',
    formats: ['qr', 'pdf417', 'datamatrix'],
    tryHarder: true,
  });

  if (!hits[0]) return null;

  const { text, format, confidence, rotation, quality } = hits[0];
  return { text, format, confidence, rotation, quality };
}

The returned quality fields are evidence, not a promise that a result should be acted on. Applications should still debounce repeated results, cap frame dimensions and require a stable payload when the surrounding workflow is sensitive. A failed or incoherent frame must produce no application action.

The current detector contracts expose quarter-turn and, where supported by the camera profile, 45-degree orientation metadata. Arbitrary perspective, blur, glare and severe module loss remain image-quality problems, not options that can be solved by setting tryHarder forever.

Lower-level image pipeline

Use the image primitives when you already own a binary image or need a format-specific detector:

import {
  LuminanceSource,
  binarize,
} from '@sythos/js_barcode_universal';
import {
  detectAndDecodeQR,
} from '@sythos/js_barcode_universal/qr';

const source = LuminanceSource.fromImageData(image);
const binary = binarize(source, 'auto');
const qrHits = detectAndDecodeQR(binary);

for (const hit of qrHits) {
  console.log(hit.text, hit.corners);
}

The lower-level QR detector consumes a BitMatrix containing the complete binarized image. Its exact decoder consumes an already sampled, square symbol without a quiet zone. That distinction matters:

import { decodeQR } from '@sythos/js_barcode_universal/qr';

// sampledMatrix must be the exact QR module grid, not a camera frame.
const exact = decodeQR(sampledMatrix);

Use the root reader unless you have a good reason to own detection, sampling and format selection yourself.

Accuracy and safety boundaries

The reader is designed to reject partial or ambiguous symbols. It cannot make a low-resolution or badly exposed photograph trustworthy by returning a guess. Keep image dimensions within a practical application budget (the project’s security guidance calls out a high but finite image-pixel ceiling), resize oversized photos before scanning, and validate any action derived from text.