UNPKG

@ericblade/quagga2

Version:

An advanced barcode-scanner written in JavaScript

1,024 lines (779 loc) 28.5 kB
/* eslint-disable max-classes-per-file */ // Type definitions for QuaggaJS v0.12.1 (2017-10-19) // Project: http://serratus.github.io/quaggaJS/ // Definitions by: Cam Birch, Peter Horwood aka Madman Pierre, Dan Manastireanu <https://github.com/danmana> import { vec2 } from 'gl-matrix'; // import SubImage from '../src/common/subImage'; // import ImageWrapper from '../src/common/image_wrapper'; // export { SubImage, ImageWrapper }; declare const Quagga: QuaggaJSStatic; export default Quagga; // There are many different spots inside Quagga where we refer to an X/Y position of something, but it has entirely different // contextual meaning. This allows us to create a type that is branded by name, and therefore these variables cannot be directly // mixed up with each other, without explicitly forcing it to happen. Good. export interface XYObject<T extends string> { type: T; x: number; y: number; } // TODO: fill this in from cv_utils#imageRef export type ImageRef = XYObject<'ImageRef'>; export type XYSize = XYObject<'XYSize'>; export type Point = XYObject<'Point'>; export type SparseImageWrapper = { data: TypedArray | Array<number> | null; size: XYSize; }; export type WrapperIndexMapping = { x: Array<number>; y: Array<number>; }; // eslint-disable-next-line @typescript-eslint/class-name-casing export type Moment = { m00: number; m01: number; m02: number; m10: number; m11: number; m20: number; rad: number; theta: number; vec?: vec2; }; export class ImageWrapper { data: TypedArray | Array<number>; size: XYSize; indexMapping?: WrapperIndexMapping; constructor( size: XYSize, data?: TypedArray | Array<number>, ArrayType?: TypedArrayConstructor | ArrayConstructor, initialize?: boolean ); inImageWithBorder(imgRef: ImageRef, border: number): boolean; subImageAsCopy(imageWrapper: ImageWrapper, from: XYSize): ImageWrapper; get(x: number, y: number): number; getSafe(x: number, y: number): number; set(x: number, y: number, value: number): ImageWrapper; zeroBorder(): ImageWrapper; moments(labelCount: any): Array<Moment>; getAsRGBA(scale?: number): Uint8ClampedArray; show(canvas: HTMLCanvasElement, scale?: number): void; overlay(canvas: HTMLCanvasElement, scale: number, from: XYSize): void; } export class SubImage { I: ImageWrapper | SparseImageWrapper; data: ImageWrapper['data']; originalSize: ImageRef; from: ImageRef; size: ImageRef; constructor(from: ImageRef, size: ImageRef, I: SparseImageWrapper); get(x: number, y: number): number; show(canvas: HTMLCanvasElement, scale: number): void; updateData(image: ImageWrapper): void; updateFrom(from: ImageRef): void; } export type QuaggaImageData = Array<number>; export type BarcodeReaderType = string; export interface BarcodeReaderConfig { normalizeBarSpaceWidth?: boolean, supplements?: Array<BarcodeReaderType>, } export enum BarcodeDirection { Forward = 1, Reverse = -1, } type BarcodeFormat = string; export interface BarcodeCorrection { bar: number; space: number; } export interface BarcodePosition { end: number; endCounter?: number; error?: number; start: number; startCounter?: number; } export interface BarcodeInfo extends BarcodePosition { code: number; correction?: BarcodeCorrection; } export interface Barcode { code: string; codeset?: number; correction?: BarcodeCorrection; decodedCodes?: Array<string | BarcodeInfo | BarcodePosition>; direction?: BarcodeDirection; end: number; endInfo?: BarcodePosition; format: BarcodeFormat; start: number; startInfo: BarcodePosition; supplement?: Barcode; } export interface ThresholdSize { counts: number; max: number; min: number; size: number; } export interface Threshold { bar: { narrow: ThresholdSize; wide: ThresholdSize; }; space: { narrow: ThresholdSize; wide: ThresholdSize; }; } export declare module Readers { export abstract class BarcodeReader { _row: Array<number>; SINGLE_CODE_ERROR: number; FORMAT: BarcodeFormat; CONFIG_KEYS: BarcodeReaderConfig; static get Exception(): { CodeNotFoundException: string; PatternNotFoundException: string; StartNotFoundException: string; }; constructor(config: BarcodeReaderConfig, supplements?: Array<BarcodeReader>); abstract decode(row?: Array<number>, start?: BarcodePosition | number): Barcode | null; decodePattern(pattern: Array<number>): Barcode | null; protected _nextUnset(line: ReadonlyArray<number>, start?: number): number; protected _matchPattern(counter: ReadonlyArray<number>, code: ReadonlyArray<number>, maxSingleError?: number): number; protected _nextSet(line: ReadonlyArray<number>, offset?: number): number; protected _correctBars(counter: Array<number>, correction: number, indices: Array<number>): void; protected _matchRange(start: number, end: number, value: number): boolean; protected _fillCounters(offset?: number, end?: number, isWhite?: boolean): number[]; protected _toCounters(start: number, counters: Uint16Array | Array<number>): number[] | Uint16Array; } export class TwoOfFiveReader extends BarcodeReader { FORMAT: string; SINGLE_CODE_ERROR: number; AVG_CODE_ERROR: number; decode(row?: Array<number>, start?: BarcodePosition): Barcode | null; protected _findPattern(pattern: ReadonlyArray<number>, offset: number, isWhite?: boolean, tryHarder?: boolean): BarcodeInfo | null; protected _findStart(): BarcodePosition | null; protected _verifyTrailingWhitespace(endInfo: BarcodeInfo): BarcodePosition | null; protected _findEnd(): BarcodePosition | null; protected _verifyCounterLength(counters: Array<number>): boolean; protected _decodeCode(counter: ReadonlyArray<number>): BarcodeInfo | null; protected _decodePayload(counters: ReadonlyArray<number>, result: Array<string>, decodedCodes: Array<BarcodeInfo | BarcodePosition>): BarcodeInfo | null; } export class NewCodabarReader extends BarcodeReader { FORMAT: string; decode(row?: Array<number>, start?: BarcodePosition | number | null): Barcode | null; protected _computeAlternatingThreshold(offset: number, end: number): number; protected _toPattern(offset: number): number; protected _isStartEnd(pattern: number): boolean; protected _sumCounters(start: number, end: number): number; protected _findStart(): BarcodePosition | null; protected _patternToChar(pattern: number): string | null; protected _calculatePatternLength(offset: number): number; protected _verifyWhitespace(startCounter: number, endCounter: number): boolean; protected _charToPattern(char: string): number; protected _thresholdResultPattern(result: ReadonlyArray<string>, startCounter: number): Threshold; protected _validateResult(result: ReadonlyArray<string>, startCounter: number): boolean; } export class Code128Reader extends BarcodeReader { CODE_SHIFT: number; CODE_C: number; CODE_B: number; CODE_A: number; START_CODE_A: number; START_CODE_B: number; START_CODE_C: number; STOP_CODE: number; CODE_PATTERN: number[][]; SINGLE_CODE_ERROR: number; AVG_CODE_ERROR: number; FORMAT: string; MODULE_INDICES: { bar: number[]; space: number[]; }; decode(row?: Array<number>, start?: BarcodePosition): Barcode | null; calculateCorrection(expected: ReadonlyArray<number>, normalized: ReadonlyArray<number>, indices: ReadonlyArray<number>): number; protected _decodeCode(start: number, correction?: BarcodeCorrection): BarcodeInfo | null; protected _correct(counter: Array<number>, correction: BarcodeCorrection): void; protected _findStart(): BarcodeInfo | null; protected _verifyTrailingWhitespace(endInfo: BarcodeInfo): BarcodeInfo | null; } export class Code39Reader extends BarcodeReader { FORMAT: string; decode(row?: Array<number>, start?: BarcodePosition | number | null): Barcode | null; protected _findStart(): BarcodePosition | null; protected _toPattern(counters: Uint16Array): number; protected _findNextWidth(counters: Uint16Array, current: number): number; protected _patternToChar(pattern: number): string | null; protected _verifyTrailingWhitespace(lastStart: number, nextStart: number, counters: Uint16Array): boolean; } export class Code32Reader extends Code39Reader { FORMAT: string; decode(row?: Array<number>, start?: BarcodePosition): Barcode | null; protected _decodeCode32(code: string): string | null; protected _checkChecksum(code: string): boolean; } export class Code39VINReader extends Code39Reader { FORMAT: string; decode(row?: Array<number>, start?: BarcodePosition): Barcode | null; protected _checkChecksum(code: string): boolean; } export class Code93Reader extends BarcodeReader { FORMAT: string; decode(row?: Array<number>, start?: BarcodePosition | number | null): Barcode | null; protected _patternToChar(pattern: number): string | null; protected _toPattern(counters: Uint16Array): number; protected _findStart(): BarcodePosition | null; protected _verifyEnd(lastStart: number, nextStart: number): boolean; protected _decodeExtended(charArray: Array<string>): string[] | null; protected _matchCheckChar(charArray: Array<string>, index: number, maxWeight: number): boolean; protected _verifyChecksums(charArray: Array<string>): boolean; } export class EANReader extends BarcodeReader { FORMAT: string; SINGLE_CODE_ERROR: number; STOP_PATTERN: number[]; constructor(config?: BarcodeReaderConfig, supplements?: Array<BarcodeReader>); decode(row?: Array<number>, start?: BarcodePosition | number): Barcode | null; protected _findPattern(pattern: ReadonlyArray<number>, offset: number, isWhite: boolean, tryHarder: boolean): BarcodePosition | null; protected _decodeCode(start: number, coderange?: number): BarcodeInfo | null; protected _findStart(): BarcodePosition | null; protected _decodePayload(inCode: BarcodePosition, result: Array<number>, decodedCodes: Array<BarcodePosition>): BarcodeInfo | null; protected _verifyTrailingWhitespace(endInfo: BarcodePosition): BarcodePosition | null; protected _findEnd(offset: number, isWhite: boolean): BarcodePosition | null; protected _checksum(result: Array<number>): boolean; } export class EAN2Reader extends EANReader { FORMAT: string; decode(row?: Array<number>, start?: number): Barcode | null; } export class EAN5Reader extends EANReader { FORMAT: string; decode(row?: Array<number>, start?: number): Barcode | null; } export class EAN8Reader extends EANReader { FORMAT: string; protected _decodePayload(inCode: BarcodePosition, result: Array<number>, decodedCodes: Array<BarcodePosition>): BarcodeInfo | null; } export class I2of5Reader extends BarcodeReader { SINGLE_CODE_ERROR: number; AVG_CODE_ERROR: number; START_PATTERN: number[]; STOP_PATTERN: number[]; CODE_PATTERN: number[][]; MAX_CORRECTION_FACTOR: number; FORMAT: string; constructor(opts: BarcodeReaderConfig); decode(row?: Array<number>, start?: BarcodePosition | number): Barcode | null; protected _matchPattern(counter: Array<number>, code: ReadonlyArray<number>): number; protected _findPattern(pattern: ReadonlyArray<number>, offset?: number, isWhite?: boolean, tryHarder?: boolean): BarcodePosition | null; protected _findStart(): BarcodePosition | null; protected _verifyTrailingWhitespace(endInfo: BarcodePosition): BarcodePosition | null; protected _findEnd(): BarcodePosition | null; protected _decodePair(counterPair: Array<Array<number>>): Array<BarcodeInfo> | null; protected _decodeCode(counter: Array<number>): BarcodeInfo | null; protected _decodePayload(counters: ReadonlyArray<number>, result: Array<string>, decodedCodes: Array<BarcodeInfo | BarcodePosition>): Array<BarcodeInfo> | null; protected _verifyCounterLength(counters: Array<number>): boolean; } export class UPCEReader extends EANReader { CODE_FREQUENCY: number[][]; STOP_PATTERN: number[]; FORMAT: string; protected _decodePayload(inCode: BarcodePosition, result: Array<number>, decodedCodes: Array<BarcodePosition>): BarcodeInfo | null; protected _determineParity(codeFrequency: number, result: Array<number>): boolean; protected _convertToUPCA(result: Array<number>): number[]; protected _checksum(result: Array<number>): boolean; protected _findEnd(offset: number, isWhite: boolean): BarcodePosition | null; protected _verifyTrailingWhitespace(endInfo: BarcodePosition): BarcodePosition | null; } export class UPCReader extends EANReader { FORMAT: string; decode(row?: Array<number>, start?: BarcodePosition | number): Barcode | null; } } export interface QuaggaJSStatic { /** * This method initializes the library for a given * configuration config (see below) and invokes the callback when Quagga is * ready to start. The initialization process also requests for camera * access if real-time detection is configured. */ init( config: QuaggaJSConfigObject, callback?: (err: any) => void ): Promise<void>; init( config: QuaggaJSConfigObject, callback: (err: any) => void, imageWrapper: ImageWrapper, ): Promise<void>; /** * When the library is initialized, the start() * method starts the video-stream and begins locating and decoding the * images. */ start(): void; /** * If the decoder is currently running, after calling * stop() the decoder does not process any more images. * Additionally, if a camera-stream was requested upon initialization, * this operation also disconnects the camera. */ stop(): Promise<void>; /** * Pauses processing, but does not release any handlers */ pause(): void; /** * This method registers a callback(data) function that is * called for each frame after the processing is done. The data object * contains detailed information about the success/failure of the operation. * The output varies, depending whether the detection and/or decoding were * successful or not. */ onProcessed(callback: QuaggaJSResultCallbackFunction): void; /** * Removes a callback that was previously registered with @see onProcessed */ offProcessed(callback?: QuaggaJSResultCallbackFunction): void; /** * Registers a callback(data) function which is triggered whenever a * barcode- pattern has been located and decoded successfully. The passed * data object contains information about the decoding process including the * detected code which can be obtained by calling data.codeResult.code. */ onDetected(callback: QuaggaJSResultCallbackFunction): void; /** * Removes a callback that was previously registered with @see onDetected */ offDetected(callback?: QuaggaJSResultCallbackFunction): void; ResultCollector: QuaggaJSResultCollector; registerResultCollector(resultCollector: QuaggaJSResultCollector): void; setReaders(readers: (QuaggaJSReaderConfig | string)[]): void; registerReader(name: string, reader: object): void; /** * In contrast to the calls described * above, this method does not rely on getUserMedia and operates on a single * image instead. The provided callback is the same as in onDetected and * contains the result data object. */ decodeSingle( config: QuaggaJSConfigObject, resultCallback?: QuaggaJSResultCallbackFunction ): Promise<QuaggaJSResultObject>; /** * Constructs used for debugging purposes */ ImageDebug: { drawPath: QuaggaJSDebugDrawPath; drawRect: QuaggaJSDebugDrawRect; }; ImageWrapper: ImageWrapper; /** * an object Quagga uses for drawing and processing, useful for calling code * when debugging */ canvas: { ctx: { image: CanvasRenderingContext2D; overlay: CanvasRenderingContext2D; }; dom: { image: HTMLCanvasElement; overlay: HTMLCanvasElement; }; }; CameraAccess: QuaggaJSCameraAccess; } /** * Used for accessing information about the active stream track and available video devices. */ export interface QuaggaJSCameraAccess { disableTorch(): Promise<void>; enableTorch(): Promise<void>; enumerateVideoDevices(): Promise<MediaDeviceInfo[]> | never; getActiveStreamLabel(): string; getActiveTrack(): MediaStreamTrack | null; release(): Promise<void>; request( video: HTMLVideoElement | null, videoConstraints?: MediaTrackConstraintsWithDeprecated ): Promise<void> | never; requestedVideoElement: HTMLVideoElement | null; } /** * Called whenever an item is detected or a process step has been completed. */ export interface QuaggaJSResultCallbackFunction { ( data: QuaggaJSResultObject ): void; } /** * Called to draw debugging path. The path is an array of array of 2 numbers. * The def.x specifies element in the sub array is the x, and similarly the def.y * defines the y. * typical values 0, 1, 'x', 'y' */ export interface QuaggaJSDebugDrawPath { ( path: any[], def: QuaggaJSxyDef, ctx: CanvasRenderingContext2D, style: QuaggaJSStyle ): void; } /** * Called to draw debugging Rectangle */ export interface QuaggaJSDebugDrawRect { ( pos: any[], size: QuaggaJSRectSize, ctx: CanvasRenderingContext2D, style: QuaggaJSStyle ): void; } /** * an object with an x and a y value, the x and y specify which element in * another array is the x or y value. * typical values 0, 1, 'x', 'y' */ // TODO: remove QuaggaJSxyDef from global type-defs (it's only used in image_debug, i think, which has a local definition) export interface QuaggaJSxyDef { x: any; y: any; } /** * an object with an x and a y value */ export interface QuaggaJSxy { x: number; y: number; } /** * an object with a pair of x and a y values. * Used for giving a html canvas context.strokeRect function it's x, y, width * and height values. */ export interface QuaggaJSRectSize { pos: QuaggaJSxy; size: QuaggaJSxy; } /** * an object with the styles, color can actually be a color, a gradient or a * pattern (see definitions for context.strokeStyle. But is most commonly a * colour. */ export interface QuaggaJSStyle { color: string; /* http://www.w3schools.com/tags/canvas_linewidth.asp */ lineWidth: number; } /** * Pass when creating a ResultCollector */ export interface QuaggaJSResultCollector { /** * keep track of the image producing this result */ capture?: boolean; /** * maximum number of results to store */ capacity?: number; /** * a list of codes that should not be recorded. This is effectively a list * of filters that return false. */ blacklist?: Array<QuaggaJSCodeResult>; /** * passed a QuaggaJSCodeResult, return true if you want this to be stored, * false if you don't. Note: The black list is effectively a list of filters * that return false. So if you only want to store results that are ean_13, * you would say return codeResult.format==="ean_13" */ filter?: QuaggaJSResultCollectorFilterFunction; /* * a static function that returns you a ResultCollector */ create?(param: QuaggaJSResultCollector): QuaggaJSResultCollector; getResults?(): QuaggaJSCodeResult[]; willReadFrequently?: boolean; } /** * used for ResultCollector blacklists and filters */ export interface QuaggaJSCodeResult { code?: string; format?: string; } /** * Called to filter which Results to collect in ResultCollector */ export interface QuaggaJSResultCollectorFilterFunction { ( data: QuaggaJSCodeResult ): boolean; } /** * The callbacks passed into onProcessed, onDetected and decodeSingle receive a * data object upon execution. The data object contains the following * information. Depending on the success, some fields may be undefined or just * empty. */ export interface QuaggaJSResultObject { // eslint-disable-next-line @typescript-eslint/camelcase codeResult: QuaggaJSResultObject_CodeResult; barcodes?: Array<QuaggaJSResultObject>; line: { x: number; y: number; }[]; angle: number; pattern: number[]; box: number[][]; boxes: number[][][]; frame?: string; } // eslint-disable-next-line @typescript-eslint/camelcase,@typescript-eslint/class-name-casing export interface QuaggaJSResultObject_CodeResult { code: string | null; start: number; end: number; codeset: number; startInfo: { error: number; code: number; start: number; end: number; }; decodedCodes: { error?: number; code: number; start: number; end: number; }[]; endInfo: { error: number; code: number; start: number; end: number; }; direction: number; format: string; } export type InputStreamType = 'VideoStream' | 'ImageStream' | 'LiveStream'; export interface QuaggaJSConfigObject { /** * The image path to load from, or a data url * Ex: '/test/fixtures/code_128/image-001.jpg' * or: 'data:image/jpg;base64,' + data */ src?: string | Uint8Array | Buffer; inputStream?: { /** * @default "Live" */ name?: string; /** * @default "LiveStream" */ type?: InputStreamType; /** * Use canvas.getContext('2d', { willReadFrequently: true }) for browser frame grabber operations * @default false * ... defaulting false because historically this wasn't an option, so i don't want to change behavior */ willReadFrequently?: boolean; target?: Element | string; constraints?: MediaTrackConstraints; /** * defines rectangle of the detection/localization area. Useful when you * KNOW that certain parts of the image will not contain a barcode, also * useful when you have multiple barcodes in a row and you want to make * sure that only a code in, say the middle quarter is read not codes * above or below */ area?: { /** * @default "0%", set this and bottom to 25% if you only want to * read a 'line' that is in the middle quarter */ top?: string; /** * @default "0%" */ right?: string; /** * @default "0%" */ left?: string; /** * @default "0%", set this and top to 50% if you only want to read a * 'line' that is in the middle half */ bottom?: string; }; mime?: string; singleChannel?: boolean; size?: number; sequence?: boolean; }; /** * @default false */ debug?: boolean; /** * @default true */ locate?: boolean; /** * @default 4 */ numOfWorkers?: number; /** * This top-level property controls the scan-frequency of the video-stream. * It’s optional and defines the maximum number of scans per second. * This renders useful for cases where the scan-session is long-running and * resources such as CPU power are of concern. */ frequency?: number; decoder?: { /** * @default [ "code_128_reader" ] */ readers?: (QuaggaJSReaderConfig | QuaggaJSCodeReader)[]; debug?: { /** * @default false */ drawBoundingBox?: boolean; /** * @default false */ showFrequency?: boolean; /** * @default false */ drawScanline?: boolean; /** * @default false */ showPattern?: boolean; }; /** * The multiple property tells the decoder if it should continue decoding after finding a valid barcode. * If multiple is set to true, the results will be returned as an array of result objects. * Each object in the array will have a box, and may have a codeResult * depending on the success of decoding the individual box. */ multiple?: boolean; }; locator?: { /** * @default true */ halfSample?: boolean; /** * @default "medium" * Available values: x-small, small, medium, large, x-large */ patchSize?: string; willReadFrequently?: boolean; debug?: { /** * @default false */ showCanvas?: boolean; /** * @default false */ showPatches?: boolean; /** * @default false */ showFoundPatches?: boolean; /** * @default false */ showSkeleton?: boolean; /** * @default false */ showLabels?: boolean; /** * @default false */ showPatchLabels?: boolean; /** * @default false */ showRemainingPatchLabels?: boolean; boxFromPatches?: { /** * @default false */ showTransformed?: boolean; /** * @default false */ showTransformedBox?: boolean; /** * @default false */ showBB?: boolean; }; }; }; } export interface QuaggaJSReaderConfig { config: { supplements: string[]; }; format: string; } export interface MediaTrackConstraintsWithDeprecated extends MediaTrackConstraints { facing?: string; maxAspectRatio?: number; // i don't see this in the documentation anywhere, but it's in the original test suite... minAspectRatio?: number; } export type TypedArrayConstructor = Int8ArrayConstructor | Uint8ArrayConstructor | Uint8ClampedArrayConstructor | Int16ArrayConstructor | Uint16ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor; export type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; export type QuaggaJSCodeReader = | 'code_128_reader' | 'ean_reader' | 'ean_5_reader' | 'ean_2_reader' | 'ean_8_reader' | 'code_39_reader' | 'code_39_vin_reader' | 'codabar_reader' | 'upc_reader' | 'upc_e_reader' | 'i2of5_reader' | '2of5_reader' | 'code_93_reader' | 'code_32_reader';