/** * @fileoverview * Core libraries, interfaces, enums shared across {@class Html5Qrcode} & {@class Html5QrcodeScanner} * * @author mebjas * * The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED * http://www.denso-wave.com/qrcode/faqpatent-e.html */ /** * Code formats supported by this library. */ export enum Html5QrcodeSupportedFormats { QR_CODE = 0, AZTEC, CODABAR, CODE_39, CODE_93, CODE_128, DATA_MATRIX, MAXICODE, ITF, EAN_13, EAN_8, PDF_417, RSS_14, RSS_EXPANDED, UPC_A, UPC_E, UPC_EAN_EXTENSION, } /** {@code Html5QrcodeSupportedFormats} to friendly name map. */ const html5QrcodeSupportedFormatsTextMap : Map = new Map( [ [ Html5QrcodeSupportedFormats.QR_CODE, "QR_CODE" ], [ Html5QrcodeSupportedFormats.AZTEC, "AZTEC" ], [ Html5QrcodeSupportedFormats.CODABAR, "CODABAR" ], [ Html5QrcodeSupportedFormats.CODE_39, "CODE_39" ], [ Html5QrcodeSupportedFormats.CODE_93, "CODE_93" ], [ Html5QrcodeSupportedFormats.CODE_128, "CODE_128" ], [ Html5QrcodeSupportedFormats.DATA_MATRIX, "DATA_MATRIX" ], [ Html5QrcodeSupportedFormats.MAXICODE, "MAXICODE" ], [ Html5QrcodeSupportedFormats.ITF, "ITF" ], [ Html5QrcodeSupportedFormats.EAN_13, "EAN_13" ], [ Html5QrcodeSupportedFormats.EAN_8, "EAN_8" ], [ Html5QrcodeSupportedFormats.PDF_417, "PDF_417" ], [ Html5QrcodeSupportedFormats.RSS_14, "RSS_14" ], [ Html5QrcodeSupportedFormats.RSS_EXPANDED, "RSS_EXPANDED" ], [ Html5QrcodeSupportedFormats.UPC_A, "UPC_A" ], [ Html5QrcodeSupportedFormats.UPC_E, "UPC_E" ], [ Html5QrcodeSupportedFormats.UPC_EAN_EXTENSION, "UPC_EAN_EXTENSION" ] ] ); /** * Indicates the type of decoded text. * * Note: this is very experimental in nature at the moment. */ export enum DecodedTextType { UNKNOWN = 0, URL, } /** Returns true if the passed object instance is a valid format. */ export function isValidHtml5QrcodeSupportedFormats(format: any): boolean { return Object.values(Html5QrcodeSupportedFormats).includes(format); } /** * Types of scans supported by the library */ export enum Html5QrcodeScanType { SCAN_TYPE_CAMERA = 0, // Camera based scanner. SCAN_TYPE_FILE = 1 // File based scanner. } /** * Constants used in QR code library. */ export class Html5QrcodeConstants { static GITHUB_PROJECT_URL: string = "https://github.com/mebjas/html5-qrcode"; static SCAN_DEFAULT_FPS = 2; static DEFAULT_DISABLE_FLIP = false; static DEFAULT_REMEMBER_LAST_CAMERA_USED = true; static DEFAULT_SUPPORTED_SCAN_TYPE = [ Html5QrcodeScanType.SCAN_TYPE_CAMERA, Html5QrcodeScanType.SCAN_TYPE_FILE]; } /** Defines dimension for QR Code Scanner. */ export interface QrDimensions { width: number; height: number; } /** * A function that takes in the width and height of the video stream * and returns QrDimensions. * * Viewfinder refers to the video showing camera stream. */ export type QrDimensionFunction = (viewfinderWidth: number, viewfinderHeight: number) => QrDimensions; /** * Defines bounds of detected QR code w.r.t the scan region. */ export interface QrBounds extends QrDimensions { x: number; y: number; } /** Format of detected code. */ export class QrcodeResultFormat { public readonly format: Html5QrcodeSupportedFormats; public readonly formatName: string; private constructor( format: Html5QrcodeSupportedFormats, formatName: string) { this.format = format; this.formatName = formatName; } public toString(): string { return this.formatName; } public static create(format: Html5QrcodeSupportedFormats) { if (!html5QrcodeSupportedFormatsTextMap.has(format)) { throw `${format} not in html5QrcodeSupportedFormatsTextMap`; } return new QrcodeResultFormat( format, html5QrcodeSupportedFormatsTextMap.get(format)!); } } /** Data class for QR code result used for debugging. */ export interface QrcodeResultDebugData { /** Name of the decoder that was used for decoding. */ decoderName?: string; } /** * Detailed scan result. */ export interface QrcodeResult { /** Decoded text. */ text: string; /** Format that was successfully scanned. */ format?: QrcodeResultFormat, /** * The bounds of the decoded QR code or bar code in the whole stream of * image. * * Note: this is experimental, and not fully supported. */ bounds?: QrBounds; /** * If the decoded text from the QR code or bar code is of a known type like * url or upi id or email id. * * Note: this is experimental, and not fully supported. */ decodedTextType?: DecodedTextType; /** Data class for QR code result used for debugging. */ debugData?: QrcodeResultDebugData; } /** * QrCode result object. */ export interface Html5QrcodeResult { decodedText: string; result: QrcodeResult; } /** * Static factory for creating {@interface Html5QrcodeResult} instance. */ export class Html5QrcodeResultFactory { static createFromText(decodedText: string): Html5QrcodeResult { let qrcodeResult = { text: decodedText }; return { decodedText: decodedText, result: qrcodeResult }; } static createFromQrcodeResult(qrcodeResult: QrcodeResult) : Html5QrcodeResult { return { decodedText: qrcodeResult.text, result: qrcodeResult }; } } /** * Different kind of errors that can lead to scanning error. */ export enum Html5QrcodeErrorTypes { UNKWOWN_ERROR = 0, IMPLEMENTATION_ERROR = 1, NO_CODE_FOUND_ERROR = 2 } /** * Interface for scan error response. */ export interface Html5QrcodeError { errorMessage: string; type: Html5QrcodeErrorTypes; } /** * Static factory for creating {@interface Html5QrcodeError} instance. */ export class Html5QrcodeErrorFactory { static createFrom(error: any): Html5QrcodeError { return { errorMessage: error, type: Html5QrcodeErrorTypes.UNKWOWN_ERROR }; } } /** * Type for a callback for a successful code scan. */ export type QrcodeSuccessCallback = (decodedText: string, result: Html5QrcodeResult) => void; /** * Type for a callback for failure during code scan. */ export type QrcodeErrorCallback = (errorMessage: string, error: Html5QrcodeError) => void; /** Code decoder interface. */ export interface QrcodeDecoderAsync { /** * Decodes content of the canvas to find a valid QR code or bar code. * * @param canvas a valid html5 canvas element. */ decodeAsync(canvas: HTMLCanvasElement): Promise; } /** * Code robust decoder interface. * *

A robust decoder may sacrifice latency of scanning for scanning quality. * Ideal for file scan kind of operation. */ export interface RobustQrcodeDecoderAsync extends QrcodeDecoderAsync { /** * Decodes content of the canvas to find a valid QR code or bar code. * *

The method implementation will run the decoder more robustly at the * expense of latency. * * @param canvas a valid html5 canvas element. */ decodeRobustlyAsync(canvas: HTMLCanvasElement): Promise; } /** Interface for logger. */ export interface Logger { log(message: string): void; warn(message: string): void; logError(message: string, isExperimental?: boolean): void; logErrors(errors: Array): void; } /** * Base logger implementation based on browser console. * * This can be replaced by a custom implementation of logger. * */ export class BaseLoggger implements Logger { private verbose: boolean; public constructor(verbose: boolean) { this.verbose = verbose; } public log(message: string): void { if (this.verbose) { // eslint-disable-next-line no-console console.log(message); } } public warn(message: string): void { if (this.verbose) { // eslint-disable-next-line no-console console.warn(message); } } public logError(message: string, isExperimental?: boolean) : void { if (this.verbose || isExperimental === true) { // eslint-disable-next-line no-console console.error(message); } } public logErrors(errors: Array): void { if (errors.length === 0) { throw "Logger#logError called without arguments"; } if (this.verbose) { // eslint-disable-next-line no-console console.error(errors); } } } //#region global functions /** Returns true if the {@param obj} is null or undefined. */ export function isNullOrUndefined(obj?: any) { return (typeof obj === "undefined") || obj === null; } /** Clips the {@code value} between {@code minValue} and {@code maxValue}. */ export function clip(value: number, minValue: number, maxValue: number) { if (value > maxValue) { return maxValue; } if (value < minValue) { return minValue; } return value; } //#endregion