Add barcode-detector-api-polyfill dependency and update environment variable declarations in SvelteKit project
CI / build (push) Has been skipped
CI / deploy (push) Successful in 1m50s

This commit is contained in:
eewing
2026-02-17 14:58:53 -06:00
parent cff20a652a
commit 9022114c8d
2137 changed files with 201996 additions and 762 deletions
+16
View File
@@ -0,0 +1,16 @@
import { BrowserCodeReader } from './BrowserCodeReader';
/**
* Aztec Code reader to use from browser.
*
* @class BrowserAztecCodeReader
* @extends {BrowserCodeReader}
*/
export declare class BrowserAztecCodeReader extends BrowserCodeReader {
/**
* Creates an instance of BrowserAztecCodeReader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
*
* @memberOf BrowserAztecCodeReader
*/
constructor(timeBetweenScansMillis?: number);
}
+19
View File
@@ -0,0 +1,19 @@
import { BrowserCodeReader } from './BrowserCodeReader';
import AztecReader from '../core/aztec/AztecReader';
/**
* Aztec Code reader to use from browser.
*
* @class BrowserAztecCodeReader
* @extends {BrowserCodeReader}
*/
export class BrowserAztecCodeReader extends BrowserCodeReader {
/**
* Creates an instance of BrowserAztecCodeReader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
*
* @memberOf BrowserAztecCodeReader
*/
constructor(timeBetweenScansMillis = 500) {
super(new AztecReader(), timeBetweenScansMillis);
}
}
+15
View File
@@ -0,0 +1,15 @@
import { BrowserCodeReader } from './BrowserCodeReader';
import DecodeHintType from '../core/DecodeHintType';
/**
* @deprecated Moving to @zxing/browser
*
* Barcode reader reader to use from browser.
*/
export declare class BrowserBarcodeReader extends BrowserCodeReader {
/**
* Creates an instance of BrowserBarcodeReader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
* @param {Map<DecodeHintType, any>} hints
*/
constructor(timeBetweenScansMillis?: number, hints?: Map<DecodeHintType, any>);
}
+17
View File
@@ -0,0 +1,17 @@
import { BrowserCodeReader } from './BrowserCodeReader';
import MultiFormatOneDReader from '../core/oned/MultiFormatOneDReader';
/**
* @deprecated Moving to @zxing/browser
*
* Barcode reader reader to use from browser.
*/
export class BrowserBarcodeReader extends BrowserCodeReader {
/**
* Creates an instance of BrowserBarcodeReader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
* @param {Map<DecodeHintType, any>} hints
*/
constructor(timeBetweenScansMillis = 500, hints) {
super(new MultiFormatOneDReader(hints), timeBetweenScansMillis, hints);
}
}
+411
View File
@@ -0,0 +1,411 @@
import BinaryBitmap from '../core/BinaryBitmap';
import DecodeHintType from '../core/DecodeHintType';
import Reader from '../core/Reader';
import Result from '../core/Result';
import { DecodeContinuouslyCallback } from './DecodeContinuouslyCallback';
import { HTMLVisualMediaElement } from './HTMLVisualMediaElement';
import { VideoInputDevice } from './VideoInputDevice';
/**
* @deprecated Moving to @zxing/browser
*
* Base class for browser code reader.
*/
export declare class BrowserCodeReader {
protected readonly reader: Reader;
protected timeBetweenScansMillis: number;
protected _hints?: Map<DecodeHintType, any>;
/**
* If navigator is present.
*/
get hasNavigator(): boolean;
/**
* If mediaDevices under navigator is supported.
*/
get isMediaDevicesSuported(): boolean;
/**
* If enumerateDevices under navigator is supported.
*/
get canEnumerateDevices(): boolean;
/**
* This will break the loop.
*/
private _stopContinuousDecode;
/**
* This will break the loop.
*/
private _stopAsyncDecode;
/**
* Delay time between decode attempts made by the scanner.
*/
protected _timeBetweenDecodingAttempts: number;
/** Time between two decoding tries in milli seconds. */
get timeBetweenDecodingAttempts(): number;
/**
* Change the time span the decoder waits between two decoding tries.
*
* @param {number} millis Time between two decoding tries in milli seconds.
*/
set timeBetweenDecodingAttempts(millis: number);
/**
* The HTML canvas element, used to draw the video or image's frame for decoding.
*/
protected captureCanvas: HTMLCanvasElement;
/**
* The HTML canvas element context.
*/
protected captureCanvasContext: CanvasRenderingContext2D;
/**
* The HTML image element, used as a fallback for the video element when decoding.
*/
protected imageElement: HTMLImageElement;
/**
* Should contain the current registered listener for image loading,
* used to unregister that listener when needed.
*/
protected imageLoadedListener: EventListener;
/**
* The stream output from camera.
*/
protected stream: MediaStream;
/**
* The HTML video element, used to display the camera stream.
*/
protected videoElement: HTMLVideoElement;
/**
* Should contain the current registered listener for video loaded-metadata,
* used to unregister that listener when needed.
*/
protected videoCanPlayListener: EventListener;
/**
* Should contain the current registered listener for video play-ended,
* used to unregister that listener when needed.
*/
protected videoEndedListener: EventListener;
/**
* Should contain the current registered listener for video playing,
* used to unregister that listener when needed.
*/
protected videoPlayingEventListener: EventListener;
/**
* Sets the hints.
*/
set hints(hints: Map<DecodeHintType, any>);
/**
* Sets the hints.
*/
get hints(): Map<DecodeHintType, any>;
/**
* Creates an instance of BrowserCodeReader.
* @param {Reader} reader The reader instance to decode the barcode
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent successful decode tries
*
* @memberOf BrowserCodeReader
*/
constructor(reader: Reader, timeBetweenScansMillis?: number, _hints?: Map<DecodeHintType, any>);
/**
* Lists all the available video input devices.
*/
listVideoInputDevices(): Promise<MediaDeviceInfo[]>;
/**
* Obtain the list of available devices with type 'videoinput'.
*
* @returns {Promise<VideoInputDevice[]>} an array of available video input devices
*
* @memberOf BrowserCodeReader
*
* @deprecated Use `listVideoInputDevices` instead.
*/
getVideoInputDevices(): Promise<VideoInputDevice[]>;
/**
* Let's you find a device using it's Id.
*/
findDeviceById(deviceId: string): Promise<MediaDeviceInfo>;
/**
* Decodes the barcode from the device specified by deviceId while showing the video in the specified video element.
*
* @param deviceId the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
* @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns The decoding result.
*
* @memberOf BrowserCodeReader
*
* @deprecated Use `decodeOnceFromVideoDevice` instead.
*/
decodeFromInputVideoDevice(deviceId?: string, videoSource?: string | HTMLVideoElement): Promise<Result>;
/**
* In one attempt, tries to decode the barcode from the device specified by deviceId while showing the video in the specified video element.
*
* @param deviceId the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
* @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeOnceFromVideoDevice(deviceId?: string, videoSource?: string | HTMLVideoElement): Promise<Result>;
/**
* In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
*
* @param constraints the media stream constraints to get s valid media stream to decode from
* @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeOnceFromConstraints(constraints: MediaStreamConstraints, videoSource?: string | HTMLVideoElement): Promise<Result>;
/**
* In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
*
* @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
* @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeOnceFromStream(stream: MediaStream, videoSource?: string | HTMLVideoElement): Promise<Result>;
/**
* Continuously decodes the barcode from the device specified by device while showing the video in the specified video element.
*
* @param {string|null} [deviceId] the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
* @param {string|HTMLVideoElement|null} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<void>}
*
* @memberOf BrowserCodeReader
*
* @deprecated Use `decodeFromVideoDevice` instead.
*/
decodeFromInputVideoDeviceContinuously(deviceId: string | null, videoSource: string | HTMLVideoElement | null, callbackFn: DecodeContinuouslyCallback): Promise<void>;
/**
* Continuously tries to decode the barcode from the device specified by device while showing the video in the specified video element.
*
* @param {string|null} [deviceId] the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
* @param {string|HTMLVideoElement|null} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<void>}
*
* @memberOf BrowserCodeReader
*/
decodeFromVideoDevice(deviceId: string | null, videoSource: string | HTMLVideoElement | null, callbackFn: DecodeContinuouslyCallback): Promise<void>;
/**
* Continuously tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
*
* @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
* @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeFromConstraints(constraints: MediaStreamConstraints, videoSource: string | HTMLVideoElement, callbackFn: DecodeContinuouslyCallback): Promise<void>;
/**
* In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
*
* @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
* @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeFromStream(stream: MediaStream, videoSource: string | HTMLVideoElement, callbackFn: DecodeContinuouslyCallback): Promise<void>;
/**
* Breaks the decoding loop.
*/
stopAsyncDecode(): void;
/**
* Breaks the decoding loop.
*/
stopContinuousDecode(): void;
/**
* Sets the new stream and request a new decoding-with-delay.
*
* @param stream The stream to be shown in the video element.
* @param decodeFn A callback for the decode method.
*/
protected attachStreamToVideo(stream: MediaStream, videoSource: string | HTMLVideoElement): Promise<HTMLVideoElement>;
/**
*
* @param videoElement
*/
protected playVideoOnLoadAsync(videoElement: HTMLVideoElement): Promise<void>;
/**
* Binds listeners and callbacks to the videoElement.
*
* @param element
* @param callbackFn
*/
protected playVideoOnLoad(element: HTMLVideoElement, callbackFn: EventListener): void;
/**
* Checks if the given video element is currently playing.
*/
isVideoPlaying(video: HTMLVideoElement): boolean;
/**
* Just tries to play the video and logs any errors.
* The play call is only made is the video is not already playing.
*/
tryPlayVideo(videoElement: HTMLVideoElement): Promise<void>;
/**
* Searches and validates a media element.
*/
getMediaElement(mediaElementId: string, type: string): HTMLVisualMediaElement;
/**
* Decodes the barcode from an image.
*
* @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
* @param {string} [url]
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeFromImage(source?: string | HTMLImageElement, url?: string): Promise<Result>;
/**
* Decodes the barcode from a video.
*
* @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
* @param {string} [url]
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeFromVideo(source?: string | HTMLVideoElement, url?: string): Promise<Result>;
/**
* Decodes continuously the barcode from a video.
*
* @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
* @param {string} [url]
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*
* @experimental
*/
decodeFromVideoContinuously(source: string | HTMLVideoElement | null, url: string | null, callbackFn: DecodeContinuouslyCallback): Promise<void>;
/**
* Decodes something from an image HTML element.
*/
decodeFromImageElement(source: string | HTMLImageElement): Promise<Result>;
/**
* Decodes something from an image HTML element.
*/
decodeFromVideoElement(source: string | HTMLVideoElement): Promise<Result>;
/**
* Decodes something from an image HTML element.
*/
decodeFromVideoElementContinuously(source: string | HTMLVideoElement, callbackFn: DecodeContinuouslyCallback): Promise<void>;
/**
* Sets up the video source so it can be decoded when loaded.
*
* @param source The video source element.
*/
private _decodeFromVideoElementSetup;
/**
* Decodes an image from a URL.
*/
decodeFromImageUrl(url?: string): Promise<Result>;
/**
* Decodes an image from a URL.
*/
decodeFromVideoUrl(url: string): Promise<Result>;
/**
* Decodes an image from a URL.
*
* @experimental
*/
decodeFromVideoUrlContinuously(url: string, callbackFn: DecodeContinuouslyCallback): Promise<void>;
private _decodeOnLoadImage;
private _decodeOnLoadVideo;
private _decodeOnLoadVideoContinuously;
isImageLoaded(img: HTMLImageElement): boolean;
prepareImageElement(imageSource?: HTMLImageElement | string): HTMLImageElement;
/**
* Sets a HTMLVideoElement for scanning or creates a new one.
*
* @param videoSource The HTMLVideoElement to be set.
*/
prepareVideoElement(videoSource?: HTMLVideoElement | string): HTMLVideoElement;
/**
* Tries to decode from the video input until it finds some value.
*/
decodeOnce(element: HTMLVisualMediaElement, retryIfNotFound?: boolean, retryIfChecksumOrFormatError?: boolean): Promise<Result>;
/**
* Continuously decodes from video input.
*/
decodeContinuously(element: HTMLVideoElement, callbackFn: DecodeContinuouslyCallback): void;
/**
* Gets the BinaryBitmap for ya! (and decodes it)
*/
decode(element: HTMLVisualMediaElement): Result;
/**
* Creates a binaryBitmap based in some image source.
*
* @param mediaElement HTML element containing drawable image source.
*/
createBinaryBitmap(mediaElement: HTMLVisualMediaElement): BinaryBitmap;
/**
*
*/
protected getCaptureCanvasContext(mediaElement?: HTMLVisualMediaElement): CanvasRenderingContext2D;
/**
*
*/
protected getCaptureCanvas(mediaElement?: HTMLVisualMediaElement): HTMLCanvasElement;
/**
* Overwriting this allows you to manipulate the next frame in anyway you want before decode.
*/
drawFrameOnCanvas(srcElement: HTMLVideoElement, dimensions?: {
sx: number;
sy: number;
sWidth: number;
sHeight: number;
dx: number;
dy: number;
dWidth: number;
dHeight: number;
}, canvasElementContext?: CanvasRenderingContext2D): void;
/**
* Ovewriting this allows you to manipulate the snapshot image in anyway you want before decode.
*/
drawImageOnCanvas(srcElement: HTMLImageElement, dimensions?: {
sx: number;
sy: number;
sWidth: number;
sHeight: number;
dx: number;
dy: number;
dWidth: number;
dHeight: number;
}, canvasElementContext?: CanvasRenderingContext2D): void;
/**
* Call the encapsulated readers decode
*/
decodeBitmap(binaryBitmap: BinaryBitmap): Result;
/**
* 🖌 Prepares the canvas for capture and scan frames.
*/
createCaptureCanvas(mediaElement?: HTMLVisualMediaElement): HTMLCanvasElement;
/**
* Stops the continuous scan and cleans the stream.
*/
protected stopStreams(): void;
/**
* Resets the code reader to the initial state. Cancels any ongoing barcode scanning from video or camera.
*
* @memberOf BrowserCodeReader
*/
reset(): void;
private _destroyVideoElement;
private _destroyImageElement;
/**
* Cleans canvas references 🖌
*/
private _destroyCaptureCanvas;
/**
* Defines what the videoElement src will be.
*
* @param videoElement
* @param stream
*/
addVideoSource(videoElement: HTMLVideoElement, stream: MediaStream): void;
/**
* Unbinds a HTML video src property.
*
* @param videoElement
*/
private cleanVideoSource;
}
+872
View File
@@ -0,0 +1,872 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import ArgumentException from '../core/ArgumentException';
import BinaryBitmap from '../core/BinaryBitmap';
import ChecksumException from '../core/ChecksumException';
import HybridBinarizer from '../core/common/HybridBinarizer';
import FormatException from '../core/FormatException';
import NotFoundException from '../core/NotFoundException';
import { HTMLCanvasElementLuminanceSource } from './HTMLCanvasElementLuminanceSource';
import { VideoInputDevice } from './VideoInputDevice';
/**
* @deprecated Moving to @zxing/browser
*
* Base class for browser code reader.
*/
export class BrowserCodeReader {
/**
* Creates an instance of BrowserCodeReader.
* @param {Reader} reader The reader instance to decode the barcode
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent successful decode tries
*
* @memberOf BrowserCodeReader
*/
constructor(reader, timeBetweenScansMillis = 500, _hints) {
this.reader = reader;
this.timeBetweenScansMillis = timeBetweenScansMillis;
this._hints = _hints;
/**
* This will break the loop.
*/
this._stopContinuousDecode = false;
/**
* This will break the loop.
*/
this._stopAsyncDecode = false;
/**
* Delay time between decode attempts made by the scanner.
*/
this._timeBetweenDecodingAttempts = 0;
}
/**
* If navigator is present.
*/
get hasNavigator() {
return typeof navigator !== 'undefined';
}
/**
* If mediaDevices under navigator is supported.
*/
get isMediaDevicesSuported() {
return this.hasNavigator && !!navigator.mediaDevices;
}
/**
* If enumerateDevices under navigator is supported.
*/
get canEnumerateDevices() {
return !!(this.isMediaDevicesSuported && navigator.mediaDevices.enumerateDevices);
}
/** Time between two decoding tries in milli seconds. */
get timeBetweenDecodingAttempts() {
return this._timeBetweenDecodingAttempts;
}
/**
* Change the time span the decoder waits between two decoding tries.
*
* @param {number} millis Time between two decoding tries in milli seconds.
*/
set timeBetweenDecodingAttempts(millis) {
this._timeBetweenDecodingAttempts = millis < 0 ? 0 : millis;
}
/**
* Sets the hints.
*/
set hints(hints) {
this._hints = hints || null;
}
/**
* Sets the hints.
*/
get hints() {
return this._hints;
}
/**
* Lists all the available video input devices.
*/
listVideoInputDevices() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.hasNavigator) {
throw new Error("Can't enumerate devices, navigator is not present.");
}
if (!this.canEnumerateDevices) {
throw new Error("Can't enumerate devices, method not supported.");
}
const devices = yield navigator.mediaDevices.enumerateDevices();
const videoDevices = [];
for (const device of devices) {
const kind = device.kind === 'video' ? 'videoinput' : device.kind;
if (kind !== 'videoinput') {
continue;
}
const deviceId = device.deviceId || device.id;
const label = device.label || `Video device ${videoDevices.length + 1}`;
const groupId = device.groupId;
const videoDevice = { deviceId, label, kind, groupId };
videoDevices.push(videoDevice);
}
return videoDevices;
});
}
/**
* Obtain the list of available devices with type 'videoinput'.
*
* @returns {Promise<VideoInputDevice[]>} an array of available video input devices
*
* @memberOf BrowserCodeReader
*
* @deprecated Use `listVideoInputDevices` instead.
*/
getVideoInputDevices() {
return __awaiter(this, void 0, void 0, function* () {
const devices = yield this.listVideoInputDevices();
return devices.map(d => new VideoInputDevice(d.deviceId, d.label));
});
}
/**
* Let's you find a device using it's Id.
*/
findDeviceById(deviceId) {
return __awaiter(this, void 0, void 0, function* () {
const devices = yield this.listVideoInputDevices();
if (!devices) {
return null;
}
return devices.find(x => x.deviceId === deviceId);
});
}
/**
* Decodes the barcode from the device specified by deviceId while showing the video in the specified video element.
*
* @param deviceId the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
* @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns The decoding result.
*
* @memberOf BrowserCodeReader
*
* @deprecated Use `decodeOnceFromVideoDevice` instead.
*/
decodeFromInputVideoDevice(deviceId, videoSource) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.decodeOnceFromVideoDevice(deviceId, videoSource);
});
}
/**
* In one attempt, tries to decode the barcode from the device specified by deviceId while showing the video in the specified video element.
*
* @param deviceId the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
* @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeOnceFromVideoDevice(deviceId, videoSource) {
return __awaiter(this, void 0, void 0, function* () {
this.reset();
let videoConstraints;
if (!deviceId) {
videoConstraints = { facingMode: 'environment' };
}
else {
videoConstraints = { deviceId: { exact: deviceId } };
}
const constraints = { video: videoConstraints };
return yield this.decodeOnceFromConstraints(constraints, videoSource);
});
}
/**
* In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
*
* @param constraints the media stream constraints to get s valid media stream to decode from
* @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeOnceFromConstraints(constraints, videoSource) {
return __awaiter(this, void 0, void 0, function* () {
const stream = yield navigator.mediaDevices.getUserMedia(constraints);
return yield this.decodeOnceFromStream(stream, videoSource);
});
}
/**
* In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
*
* @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
* @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeOnceFromStream(stream, videoSource) {
return __awaiter(this, void 0, void 0, function* () {
this.reset();
const video = yield this.attachStreamToVideo(stream, videoSource);
const result = yield this.decodeOnce(video);
return result;
});
}
/**
* Continuously decodes the barcode from the device specified by device while showing the video in the specified video element.
*
* @param {string|null} [deviceId] the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
* @param {string|HTMLVideoElement|null} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<void>}
*
* @memberOf BrowserCodeReader
*
* @deprecated Use `decodeFromVideoDevice` instead.
*/
decodeFromInputVideoDeviceContinuously(deviceId, videoSource, callbackFn) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.decodeFromVideoDevice(deviceId, videoSource, callbackFn);
});
}
/**
* Continuously tries to decode the barcode from the device specified by device while showing the video in the specified video element.
*
* @param {string|null} [deviceId] the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
* @param {string|HTMLVideoElement|null} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<void>}
*
* @memberOf BrowserCodeReader
*/
decodeFromVideoDevice(deviceId, videoSource, callbackFn) {
return __awaiter(this, void 0, void 0, function* () {
let videoConstraints;
if (!deviceId) {
videoConstraints = { facingMode: 'environment' };
}
else {
videoConstraints = { deviceId: { exact: deviceId } };
}
const constraints = { video: videoConstraints };
return yield this.decodeFromConstraints(constraints, videoSource, callbackFn);
});
}
/**
* Continuously tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
*
* @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
* @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeFromConstraints(constraints, videoSource, callbackFn) {
return __awaiter(this, void 0, void 0, function* () {
const stream = yield navigator.mediaDevices.getUserMedia(constraints);
return yield this.decodeFromStream(stream, videoSource, callbackFn);
});
}
/**
* In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
*
* @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
* @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeFromStream(stream, videoSource, callbackFn) {
return __awaiter(this, void 0, void 0, function* () {
this.reset();
const video = yield this.attachStreamToVideo(stream, videoSource);
return yield this.decodeContinuously(video, callbackFn);
});
}
/**
* Breaks the decoding loop.
*/
stopAsyncDecode() {
this._stopAsyncDecode = true;
}
/**
* Breaks the decoding loop.
*/
stopContinuousDecode() {
this._stopContinuousDecode = true;
}
/**
* Sets the new stream and request a new decoding-with-delay.
*
* @param stream The stream to be shown in the video element.
* @param decodeFn A callback for the decode method.
*/
attachStreamToVideo(stream, videoSource) {
return __awaiter(this, void 0, void 0, function* () {
const videoElement = this.prepareVideoElement(videoSource);
this.addVideoSource(videoElement, stream);
this.videoElement = videoElement;
this.stream = stream;
yield this.playVideoOnLoadAsync(videoElement);
return videoElement;
});
}
/**
*
* @param videoElement
*/
playVideoOnLoadAsync(videoElement) {
return new Promise((resolve, reject) => this.playVideoOnLoad(videoElement, () => resolve()));
}
/**
* Binds listeners and callbacks to the videoElement.
*
* @param element
* @param callbackFn
*/
playVideoOnLoad(element, callbackFn) {
this.videoEndedListener = () => this.stopStreams();
this.videoCanPlayListener = () => this.tryPlayVideo(element);
element.addEventListener('ended', this.videoEndedListener);
element.addEventListener('canplay', this.videoCanPlayListener);
element.addEventListener('playing', callbackFn);
// if canplay was already fired, we won't know when to play, so just give it a try
this.tryPlayVideo(element);
}
/**
* Checks if the given video element is currently playing.
*/
isVideoPlaying(video) {
return (video.currentTime > 0 &&
!video.paused &&
!video.ended &&
video.readyState > 2);
}
/**
* Just tries to play the video and logs any errors.
* The play call is only made is the video is not already playing.
*/
tryPlayVideo(videoElement) {
return __awaiter(this, void 0, void 0, function* () {
if (this.isVideoPlaying(videoElement)) {
console.warn('Trying to play video that is already playing.');
return;
}
try {
yield videoElement.play();
}
catch (_a) {
console.warn('It was not possible to play the video.');
}
});
}
/**
* Searches and validates a media element.
*/
getMediaElement(mediaElementId, type) {
const mediaElement = document.getElementById(mediaElementId);
if (!mediaElement) {
throw new ArgumentException(`element with id '${mediaElementId}' not found`);
}
if (mediaElement.nodeName.toLowerCase() !== type.toLowerCase()) {
throw new ArgumentException(`element with id '${mediaElementId}' must be an ${type} element`);
}
return mediaElement;
}
/**
* Decodes the barcode from an image.
*
* @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
* @param {string} [url]
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeFromImage(source, url) {
if (!source && !url) {
throw new ArgumentException('either imageElement with a src set or an url must be provided');
}
if (url && !source) {
return this.decodeFromImageUrl(url);
}
return this.decodeFromImageElement(source);
}
/**
* Decodes the barcode from a video.
*
* @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
* @param {string} [url]
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*/
decodeFromVideo(source, url) {
if (!source && !url) {
throw new ArgumentException('Either an element with a src set or an URL must be provided');
}
if (url && !source) {
return this.decodeFromVideoUrl(url);
}
return this.decodeFromVideoElement(source);
}
/**
* Decodes continuously the barcode from a video.
*
* @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
* @param {string} [url]
* @returns {Promise<Result>} The decoding result.
*
* @memberOf BrowserCodeReader
*
* @experimental
*/
decodeFromVideoContinuously(source, url, callbackFn) {
if (undefined === source && undefined === url) {
throw new ArgumentException('Either an element with a src set or an URL must be provided');
}
if (url && !source) {
return this.decodeFromVideoUrlContinuously(url, callbackFn);
}
return this.decodeFromVideoElementContinuously(source, callbackFn);
}
/**
* Decodes something from an image HTML element.
*/
decodeFromImageElement(source) {
if (!source) {
throw new ArgumentException('An image element must be provided.');
}
this.reset();
const element = this.prepareImageElement(source);
this.imageElement = element;
let task;
if (this.isImageLoaded(element)) {
task = this.decodeOnce(element, false, true);
}
else {
task = this._decodeOnLoadImage(element);
}
return task;
}
/**
* Decodes something from an image HTML element.
*/
decodeFromVideoElement(source) {
const element = this._decodeFromVideoElementSetup(source);
return this._decodeOnLoadVideo(element);
}
/**
* Decodes something from an image HTML element.
*/
decodeFromVideoElementContinuously(source, callbackFn) {
const element = this._decodeFromVideoElementSetup(source);
return this._decodeOnLoadVideoContinuously(element, callbackFn);
}
/**
* Sets up the video source so it can be decoded when loaded.
*
* @param source The video source element.
*/
_decodeFromVideoElementSetup(source) {
if (!source) {
throw new ArgumentException('A video element must be provided.');
}
this.reset();
const element = this.prepareVideoElement(source);
// defines the video element before starts decoding
this.videoElement = element;
return element;
}
/**
* Decodes an image from a URL.
*/
decodeFromImageUrl(url) {
if (!url) {
throw new ArgumentException('An URL must be provided.');
}
this.reset();
const element = this.prepareImageElement();
this.imageElement = element;
const decodeTask = this._decodeOnLoadImage(element);
element.src = url;
return decodeTask;
}
/**
* Decodes an image from a URL.
*/
decodeFromVideoUrl(url) {
if (!url) {
throw new ArgumentException('An URL must be provided.');
}
this.reset();
// creates a new element
const element = this.prepareVideoElement();
const decodeTask = this.decodeFromVideoElement(element);
element.src = url;
return decodeTask;
}
/**
* Decodes an image from a URL.
*
* @experimental
*/
decodeFromVideoUrlContinuously(url, callbackFn) {
if (!url) {
throw new ArgumentException('An URL must be provided.');
}
this.reset();
// creates a new element
const element = this.prepareVideoElement();
const decodeTask = this.decodeFromVideoElementContinuously(element, callbackFn);
element.src = url;
return decodeTask;
}
_decodeOnLoadImage(element) {
return new Promise((resolve, reject) => {
this.imageLoadedListener = () => this.decodeOnce(element, false, true).then(resolve, reject);
element.addEventListener('load', this.imageLoadedListener);
});
}
_decodeOnLoadVideo(videoElement) {
return __awaiter(this, void 0, void 0, function* () {
// plays the video
yield this.playVideoOnLoadAsync(videoElement);
// starts decoding after played the video
return yield this.decodeOnce(videoElement);
});
}
_decodeOnLoadVideoContinuously(videoElement, callbackFn) {
return __awaiter(this, void 0, void 0, function* () {
// plays the video
yield this.playVideoOnLoadAsync(videoElement);
// starts decoding after played the video
this.decodeContinuously(videoElement, callbackFn);
});
}
isImageLoaded(img) {
// During the onload event, IE correctly identifies any images that
// werent downloaded as not complete. Others should too. Gecko-based
// browsers act like NS4 in that they report this incorrectly.
if (!img.complete) {
return false;
}
// However, they do have two very useful properties: naturalWidth and
// naturalHeight. These give the true size of the image. If it failed
// to load, either of these should be zero.
if (img.naturalWidth === 0) {
return false;
}
// No other way of checking: assume its ok.
return true;
}
prepareImageElement(imageSource) {
let imageElement;
if (typeof imageSource === 'undefined') {
imageElement = document.createElement('img');
imageElement.width = 200;
imageElement.height = 200;
}
if (typeof imageSource === 'string') {
imageElement = this.getMediaElement(imageSource, 'img');
}
if (imageSource instanceof HTMLImageElement) {
imageElement = imageSource;
}
return imageElement;
}
/**
* Sets a HTMLVideoElement for scanning or creates a new one.
*
* @param videoSource The HTMLVideoElement to be set.
*/
prepareVideoElement(videoSource) {
let videoElement;
if (!videoSource && typeof document !== 'undefined') {
videoElement = document.createElement('video');
videoElement.width = 200;
videoElement.height = 200;
}
if (typeof videoSource === 'string') {
videoElement = (this.getMediaElement(videoSource, 'video'));
}
if (videoSource instanceof HTMLVideoElement) {
videoElement = videoSource;
}
// Needed for iOS 11
videoElement.setAttribute('autoplay', 'true');
videoElement.setAttribute('muted', 'true');
videoElement.setAttribute('playsinline', 'true');
return videoElement;
}
/**
* Tries to decode from the video input until it finds some value.
*/
decodeOnce(element, retryIfNotFound = true, retryIfChecksumOrFormatError = true) {
this._stopAsyncDecode = false;
const loop = (resolve, reject) => {
if (this._stopAsyncDecode) {
reject(new NotFoundException('Video stream has ended before any code could be detected.'));
this._stopAsyncDecode = undefined;
return;
}
try {
const result = this.decode(element);
resolve(result);
}
catch (e) {
const ifNotFound = retryIfNotFound && e instanceof NotFoundException;
const isChecksumOrFormatError = e instanceof ChecksumException || e instanceof FormatException;
const ifChecksumOrFormat = isChecksumOrFormatError && retryIfChecksumOrFormatError;
if (ifNotFound || ifChecksumOrFormat) {
// trying again
return setTimeout(loop, this._timeBetweenDecodingAttempts, resolve, reject);
}
reject(e);
}
};
return new Promise((resolve, reject) => loop(resolve, reject));
}
/**
* Continuously decodes from video input.
*/
decodeContinuously(element, callbackFn) {
this._stopContinuousDecode = false;
const loop = () => {
if (this._stopContinuousDecode) {
this._stopContinuousDecode = undefined;
return;
}
try {
const result = this.decode(element);
callbackFn(result, null);
setTimeout(loop, this.timeBetweenScansMillis);
}
catch (e) {
callbackFn(null, e);
const isChecksumOrFormatError = e instanceof ChecksumException || e instanceof FormatException;
const isNotFound = e instanceof NotFoundException;
if (isChecksumOrFormatError || isNotFound) {
// trying again
setTimeout(loop, this._timeBetweenDecodingAttempts);
}
}
};
loop();
}
/**
* Gets the BinaryBitmap for ya! (and decodes it)
*/
decode(element) {
// get binary bitmap for decode function
const binaryBitmap = this.createBinaryBitmap(element);
return this.decodeBitmap(binaryBitmap);
}
/**
* Creates a binaryBitmap based in some image source.
*
* @param mediaElement HTML element containing drawable image source.
*/
createBinaryBitmap(mediaElement) {
const ctx = this.getCaptureCanvasContext(mediaElement);
// doing a scan with inverted colors on the second scan should only happen for video elements
let doAutoInvert = false;
if (mediaElement instanceof HTMLVideoElement) {
this.drawFrameOnCanvas(mediaElement);
doAutoInvert = true;
}
else {
this.drawImageOnCanvas(mediaElement);
}
const canvas = this.getCaptureCanvas(mediaElement);
const luminanceSource = new HTMLCanvasElementLuminanceSource(canvas, doAutoInvert);
const hybridBinarizer = new HybridBinarizer(luminanceSource);
return new BinaryBitmap(hybridBinarizer);
}
/**
*
*/
getCaptureCanvasContext(mediaElement) {
if (!this.captureCanvasContext) {
const elem = this.getCaptureCanvas(mediaElement);
let ctx;
try {
ctx = elem.getContext('2d', { willReadFrequently: true });
}
catch (e) {
ctx = elem.getContext('2d');
}
this.captureCanvasContext = ctx;
}
return this.captureCanvasContext;
}
/**
*
*/
getCaptureCanvas(mediaElement) {
if (!this.captureCanvas) {
const elem = this.createCaptureCanvas(mediaElement);
this.captureCanvas = elem;
}
return this.captureCanvas;
}
/**
* Overwriting this allows you to manipulate the next frame in anyway you want before decode.
*/
drawFrameOnCanvas(srcElement, dimensions = {
sx: 0,
sy: 0,
sWidth: srcElement.videoWidth,
sHeight: srcElement.videoHeight,
dx: 0,
dy: 0,
dWidth: srcElement.videoWidth,
dHeight: srcElement.videoHeight,
}, canvasElementContext = this.captureCanvasContext) {
canvasElementContext.drawImage(srcElement, dimensions.sx, dimensions.sy, dimensions.sWidth, dimensions.sHeight, dimensions.dx, dimensions.dy, dimensions.dWidth, dimensions.dHeight);
}
/**
* Ovewriting this allows you to manipulate the snapshot image in anyway you want before decode.
*/
drawImageOnCanvas(srcElement, dimensions = {
sx: 0,
sy: 0,
sWidth: srcElement.naturalWidth,
sHeight: srcElement.naturalHeight,
dx: 0,
dy: 0,
dWidth: srcElement.naturalWidth,
dHeight: srcElement.naturalHeight,
}, canvasElementContext = this.captureCanvasContext) {
canvasElementContext.drawImage(srcElement, dimensions.sx, dimensions.sy, dimensions.sWidth, dimensions.sHeight, dimensions.dx, dimensions.dy, dimensions.dWidth, dimensions.dHeight);
}
/**
* Call the encapsulated readers decode
*/
decodeBitmap(binaryBitmap) {
return this.reader.decode(binaryBitmap, this._hints);
}
/**
* 🖌 Prepares the canvas for capture and scan frames.
*/
createCaptureCanvas(mediaElement) {
if (typeof document === 'undefined') {
this._destroyCaptureCanvas();
return null;
}
const canvasElement = document.createElement('canvas');
let width;
let height;
if (typeof mediaElement !== 'undefined') {
if (mediaElement instanceof HTMLVideoElement) {
width = mediaElement.videoWidth;
height = mediaElement.videoHeight;
}
else if (mediaElement instanceof HTMLImageElement) {
width = mediaElement.naturalWidth || mediaElement.width;
height = mediaElement.naturalHeight || mediaElement.height;
}
}
canvasElement.style.width = width + 'px';
canvasElement.style.height = height + 'px';
canvasElement.width = width;
canvasElement.height = height;
return canvasElement;
}
/**
* Stops the continuous scan and cleans the stream.
*/
stopStreams() {
if (this.stream) {
this.stream.getVideoTracks().forEach(t => t.stop());
this.stream = undefined;
}
if (this._stopAsyncDecode === false) {
this.stopAsyncDecode();
}
if (this._stopContinuousDecode === false) {
this.stopContinuousDecode();
}
}
/**
* Resets the code reader to the initial state. Cancels any ongoing barcode scanning from video or camera.
*
* @memberOf BrowserCodeReader
*/
reset() {
// stops the camera, preview and scan 🔴
this.stopStreams();
// clean and forget about HTML elements
this._destroyVideoElement();
this._destroyImageElement();
this._destroyCaptureCanvas();
}
_destroyVideoElement() {
if (!this.videoElement) {
return;
}
// first gives freedon to the element 🕊
if (typeof this.videoEndedListener !== 'undefined') {
this.videoElement.removeEventListener('ended', this.videoEndedListener);
}
if (typeof this.videoPlayingEventListener !== 'undefined') {
this.videoElement.removeEventListener('playing', this.videoPlayingEventListener);
}
if (typeof this.videoCanPlayListener !== 'undefined') {
this.videoElement.removeEventListener('loadedmetadata', this.videoCanPlayListener);
}
// then forgets about that element 😢
this.cleanVideoSource(this.videoElement);
this.videoElement = undefined;
}
_destroyImageElement() {
if (!this.imageElement) {
return;
}
// first gives freedon to the element 🕊
if (undefined !== this.imageLoadedListener) {
this.imageElement.removeEventListener('load', this.imageLoadedListener);
}
// then forget about that element 😢
this.imageElement.src = undefined;
this.imageElement.removeAttribute('src');
this.imageElement = undefined;
}
/**
* Cleans canvas references 🖌
*/
_destroyCaptureCanvas() {
// then forget about that element 😢
this.captureCanvasContext = undefined;
this.captureCanvas = undefined;
}
/**
* Defines what the videoElement src will be.
*
* @param videoElement
* @param stream
*/
addVideoSource(videoElement, stream) {
// Older browsers may not have `srcObject`
try {
// @note Throws Exception if interrupted by a new loaded request
videoElement.srcObject = stream;
}
catch (err) {
// @note Avoid using this in new browsers, as it is going away.
// @ts-ignore
videoElement.src = URL.createObjectURL(stream);
}
}
/**
* Unbinds a HTML video src property.
*
* @param videoElement
*/
cleanVideoSource(videoElement) {
try {
videoElement.srcObject = null;
}
catch (err) {
videoElement.src = '';
}
this.videoElement.removeAttribute('src');
}
}
@@ -0,0 +1,13 @@
import { BrowserCodeReader } from './BrowserCodeReader';
/**
* @deprecated Moving to @zxing/browser
*
* QR Code reader to use from browser.
*/
export declare class BrowserDatamatrixCodeReader extends BrowserCodeReader {
/**
* Creates an instance of BrowserQRCodeReader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
*/
constructor(timeBetweenScansMillis?: number);
}
@@ -0,0 +1,16 @@
import { BrowserCodeReader } from './BrowserCodeReader';
import DataMatrixReader from '../core/datamatrix/DataMatrixReader';
/**
* @deprecated Moving to @zxing/browser
*
* QR Code reader to use from browser.
*/
export class BrowserDatamatrixCodeReader extends BrowserCodeReader {
/**
* Creates an instance of BrowserQRCodeReader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
*/
constructor(timeBetweenScansMillis = 500) {
super(new DataMatrixReader(), timeBetweenScansMillis);
}
}
@@ -0,0 +1,14 @@
import { BrowserCodeReader } from './BrowserCodeReader';
import MultiFormatReader from '../core/MultiFormatReader';
import BinaryBitmap from '../core/BinaryBitmap';
import Result from '../core/Result';
import DecodeHintType from '../core/DecodeHintType';
export declare class BrowserMultiFormatReader extends BrowserCodeReader {
protected readonly reader: MultiFormatReader;
constructor(hints?: Map<DecodeHintType, any>, timeBetweenScansMillis?: number);
/**
* Overwrite decodeBitmap to call decodeWithState, which will pay
* attention to the hints set in the constructor function
*/
decodeBitmap(binaryBitmap: BinaryBitmap): Result;
}
+16
View File
@@ -0,0 +1,16 @@
import { BrowserCodeReader } from './BrowserCodeReader';
import MultiFormatReader from '../core/MultiFormatReader';
export class BrowserMultiFormatReader extends BrowserCodeReader {
constructor(hints = null, timeBetweenScansMillis = 500) {
const reader = new MultiFormatReader();
reader.setHints(hints);
super(reader, timeBetweenScansMillis);
}
/**
* Overwrite decodeBitmap to call decodeWithState, which will pay
* attention to the hints set in the constructor function
*/
decodeBitmap(binaryBitmap) {
return this.reader.decodeWithState(binaryBitmap);
}
}
+13
View File
@@ -0,0 +1,13 @@
import { BrowserCodeReader } from './BrowserCodeReader';
/**
* @deprecated Moving to @zxing/browser
*
* QR Code reader to use from browser.
*/
export declare class BrowserPDF417Reader extends BrowserCodeReader {
/**
* Creates an instance of BrowserPDF417Reader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
*/
constructor(timeBetweenScansMillis?: number);
}
+16
View File
@@ -0,0 +1,16 @@
import { BrowserCodeReader } from './BrowserCodeReader';
import PDF417Reader from '../core/pdf417/PDF417Reader';
/**
* @deprecated Moving to @zxing/browser
*
* QR Code reader to use from browser.
*/
export class BrowserPDF417Reader extends BrowserCodeReader {
/**
* Creates an instance of BrowserPDF417Reader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
*/
constructor(timeBetweenScansMillis = 500) {
super(new PDF417Reader(), timeBetweenScansMillis);
}
}
+13
View File
@@ -0,0 +1,13 @@
import { BrowserCodeReader } from './BrowserCodeReader';
/**
* @deprecated Moving to @zxing/browser
*
* QR Code reader to use from browser.
*/
export declare class BrowserQRCodeReader extends BrowserCodeReader {
/**
* Creates an instance of BrowserQRCodeReader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
*/
constructor(timeBetweenScansMillis?: number);
}
+16
View File
@@ -0,0 +1,16 @@
import { BrowserCodeReader } from './BrowserCodeReader';
import QRCodeReader from '../core/qrcode/QRCodeReader';
/**
* @deprecated Moving to @zxing/browser
*
* QR Code reader to use from browser.
*/
export class BrowserQRCodeReader extends BrowserCodeReader {
/**
* Creates an instance of BrowserQRCodeReader.
* @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
*/
constructor(timeBetweenScansMillis = 500) {
super(new QRCodeReader(), timeBetweenScansMillis);
}
}
+46
View File
@@ -0,0 +1,46 @@
import EncodeHintType from '../core/EncodeHintType';
/**
* @deprecated Moving to @zxing/browser
*/
declare class BrowserQRCodeSvgWriter {
private static readonly QUIET_ZONE_SIZE;
/**
* SVG markup NameSpace
*/
private static readonly SVG_NS;
/**
* Writes and renders a QRCode SVG element.
*
* @param contents
* @param width
* @param height
* @param hints
*/
write(contents: string, width: number, height: number, hints?: Map<EncodeHintType, any>): SVGSVGElement;
/**
* Renders the result and then appends it to the DOM.
*/
writeToDom(containerElement: string | HTMLElement, contents: string, width: number, height: number, hints?: Map<EncodeHintType, any>): void;
/**
* Note that the input matrix uses 0 == white, 1 == black.
* The output matrix uses 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
*/
private renderResult;
/**
* Creates a SVG element.
*
* @param w SVG's width attribute
* @param h SVG's height attribute
*/
private createSVGElement;
/**
* Creates a SVG rect element.
*
* @param x Element's x coordinate
* @param y Element's y coordinate
* @param w Element's width attribute
* @param h Element's height attribute
*/
private createSvgRectElement;
}
export { BrowserQRCodeSvgWriter };
+121
View File
@@ -0,0 +1,121 @@
import EncodeHintType from '../core/EncodeHintType';
import Encoder from '../core/qrcode/encoder/Encoder';
import ErrorCorrectionLevel from '../core/qrcode/decoder/ErrorCorrectionLevel';
import IllegalArgumentException from '../core/IllegalArgumentException';
import IllegalStateException from '../core/IllegalStateException';
/**
* @deprecated Moving to @zxing/browser
*/
class BrowserQRCodeSvgWriter {
/**
* Writes and renders a QRCode SVG element.
*
* @param contents
* @param width
* @param height
* @param hints
*/
write(contents, width, height, hints = null) {
if (contents.length === 0) {
throw new IllegalArgumentException('Found empty contents');
}
// if (format != BarcodeFormat.QR_CODE) {
// throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format)
// }
if (width < 0 || height < 0) {
throw new IllegalArgumentException('Requested dimensions are too small: ' + width + 'x' + height);
}
let errorCorrectionLevel = ErrorCorrectionLevel.L;
let quietZone = BrowserQRCodeSvgWriter.QUIET_ZONE_SIZE;
if (hints !== null) {
if (undefined !== hints.get(EncodeHintType.ERROR_CORRECTION)) {
errorCorrectionLevel = ErrorCorrectionLevel.fromString(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
}
if (undefined !== hints.get(EncodeHintType.MARGIN)) {
quietZone = Number.parseInt(hints.get(EncodeHintType.MARGIN).toString(), 10);
}
}
const code = Encoder.encode(contents, errorCorrectionLevel, hints);
return this.renderResult(code, width, height, quietZone);
}
/**
* Renders the result and then appends it to the DOM.
*/
writeToDom(containerElement, contents, width, height, hints = null) {
if (typeof containerElement === 'string') {
containerElement = document.querySelector(containerElement);
}
const svgElement = this.write(contents, width, height, hints);
if (containerElement)
containerElement.appendChild(svgElement);
}
/**
* Note that the input matrix uses 0 == white, 1 == black.
* The output matrix uses 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
*/
renderResult(code, width /*int*/, height /*int*/, quietZone /*int*/) {
const input = code.getMatrix();
if (input === null) {
throw new IllegalStateException();
}
const inputWidth = input.getWidth();
const inputHeight = input.getHeight();
const qrWidth = inputWidth + (quietZone * 2);
const qrHeight = inputHeight + (quietZone * 2);
const outputWidth = Math.max(width, qrWidth);
const outputHeight = Math.max(height, qrHeight);
const multiple = Math.min(Math.floor(outputWidth / qrWidth), Math.floor(outputHeight / qrHeight));
// Padding includes both the quiet zone and the extra white pixels to accommodate the requested
// dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
// If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
// handle all the padding from 100x100 (the actual QR) up to 200x160.
const leftPadding = Math.floor((outputWidth - (inputWidth * multiple)) / 2);
const topPadding = Math.floor((outputHeight - (inputHeight * multiple)) / 2);
const svgElement = this.createSVGElement(outputWidth, outputHeight);
for (let inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
// Write the contents of this row of the barcode
for (let inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (input.get(inputX, inputY) === 1) {
const svgRectElement = this.createSvgRectElement(outputX, outputY, multiple, multiple);
svgElement.appendChild(svgRectElement);
}
}
}
return svgElement;
}
/**
* Creates a SVG element.
*
* @param w SVG's width attribute
* @param h SVG's height attribute
*/
createSVGElement(w, h) {
const svgElement = document.createElementNS(BrowserQRCodeSvgWriter.SVG_NS, 'svg');
svgElement.setAttributeNS(null, 'height', w.toString());
svgElement.setAttributeNS(null, 'width', h.toString());
return svgElement;
}
/**
* Creates a SVG rect element.
*
* @param x Element's x coordinate
* @param y Element's y coordinate
* @param w Element's width attribute
* @param h Element's height attribute
*/
createSvgRectElement(x, y, w, h) {
const rect = document.createElementNS(BrowserQRCodeSvgWriter.SVG_NS, 'rect');
rect.setAttributeNS(null, 'x', x.toString());
rect.setAttributeNS(null, 'y', y.toString());
rect.setAttributeNS(null, 'height', w.toString());
rect.setAttributeNS(null, 'width', h.toString());
rect.setAttributeNS(null, 'fill', '#000000');
return rect;
}
}
BrowserQRCodeSvgWriter.QUIET_ZONE_SIZE = 4;
/**
* SVG markup NameSpace
*/
BrowserQRCodeSvgWriter.SVG_NS = 'http://www.w3.org/2000/svg';
export { BrowserQRCodeSvgWriter };
+49
View File
@@ -0,0 +1,49 @@
import EncodeHintType from '../core/EncodeHintType';
/**
* @deprecated Moving to @zxing/browser
*/
declare abstract class BrowserSvgCodeWriter {
/**
* Default quiet zone in pixels.
*/
private static readonly QUIET_ZONE_SIZE;
/**
* SVG markup NameSpace
*/
private static readonly SVG_NS;
/**
* A HTML container element for the image.
*/
private containerElement;
/**
* Constructs. 😉
*/
constructor(containerElement: string | HTMLElement);
/**
* Writes the QR code to a SVG and renders it in the container.
*/
write(contents: string, width: number, height: number, hints?: Map<EncodeHintType, any>): SVGSVGElement;
/**
* Encodes the content to a Barcode type.
*/
private encode;
/**
* Renders the SVG in the container.
*
* @note the input matrix uses 0 == white, 1 == black. The output matrix uses 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
*/
private renderResult;
/**
* Creates a SVG element.
*/
protected createSVGElement(w: number, h: number): SVGSVGElement;
/**
* Creates a SVG rect.
*/
protected createSvgPathPlaceholderElement(w: number, h: number): SVGPathElement;
/**
* Creates a SVG rect.
*/
protected createSvgRectElement(x: number, y: number, w: number, h: number): SVGRectElement;
}
export { BrowserSvgCodeWriter };
+129
View File
@@ -0,0 +1,129 @@
import EncodeHintType from '../core/EncodeHintType';
import Encoder from '../core/qrcode/encoder/Encoder';
import ErrorCorrectionLevel from '../core/qrcode/decoder/ErrorCorrectionLevel';
import IllegalArgumentException from '../core/IllegalArgumentException';
import IllegalStateException from '../core/IllegalStateException';
/**
* @deprecated Moving to @zxing/browser
*/
class BrowserSvgCodeWriter {
/**
* Constructs. 😉
*/
constructor(containerElement) {
if (typeof containerElement === 'string') {
this.containerElement = document.getElementById(containerElement);
}
else {
this.containerElement = containerElement;
}
}
/**
* Writes the QR code to a SVG and renders it in the container.
*/
write(contents, width, height, hints = null) {
if (contents.length === 0) {
throw new IllegalArgumentException('Found empty contents');
}
if (width < 0 || height < 0) {
throw new IllegalArgumentException('Requested dimensions are too small: ' + width + 'x' + height);
}
let quietZone = hints && hints.get(EncodeHintType.MARGIN) !== undefined
? Number.parseInt(hints.get(EncodeHintType.MARGIN).toString(), 10)
: BrowserSvgCodeWriter.QUIET_ZONE_SIZE;
const code = this.encode(hints, contents);
return this.renderResult(code, width, height, quietZone);
}
/**
* Encodes the content to a Barcode type.
*/
encode(hints, contents) {
let errorCorrectionLevel = ErrorCorrectionLevel.L;
if (hints && hints.get(EncodeHintType.ERROR_CORRECTION) !== undefined) {
errorCorrectionLevel = ErrorCorrectionLevel.fromString(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
}
const code = Encoder.encode(contents, errorCorrectionLevel, hints);
return code;
}
/**
* Renders the SVG in the container.
*
* @note the input matrix uses 0 == white, 1 == black. The output matrix uses 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
*/
renderResult(code, width /*int*/, height /*int*/, quietZone /*int*/) {
// if (this.format && format != this.format) {
// throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format)
// }
const input = code.getMatrix();
if (input === null) {
throw new IllegalStateException();
}
const inputWidth = input.getWidth();
const inputHeight = input.getHeight();
const qrWidth = inputWidth + (quietZone * 2);
const qrHeight = inputHeight + (quietZone * 2);
const outputWidth = Math.max(width, qrWidth);
const outputHeight = Math.max(height, qrHeight);
const multiple = Math.min(Math.floor(outputWidth / qrWidth), Math.floor(outputHeight / qrHeight));
// Padding includes both the quiet zone and the extra white pixels to accommodate the requested
// dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
// If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
// handle all the padding from 100x100 (the actual QR) up to 200x160.
const leftPadding = Math.floor((outputWidth - (inputWidth * multiple)) / 2);
const topPadding = Math.floor((outputHeight - (inputHeight * multiple)) / 2);
const svgElement = this.createSVGElement(outputWidth, outputHeight);
const placeholder = this.createSvgPathPlaceholderElement(width, height);
svgElement.append(placeholder);
this.containerElement.appendChild(svgElement);
// 2D loop
for (let inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
// Write the contents of this row of the barcode
for (let inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (input.get(inputX, inputY) === 1) {
const svgRectElement = this.createSvgRectElement(outputX, outputY, multiple, multiple);
svgElement.appendChild(svgRectElement);
}
}
}
return svgElement;
}
/**
* Creates a SVG element.
*/
createSVGElement(w, h) {
const el = document.createElementNS(BrowserSvgCodeWriter.SVG_NS, 'svg');
el.setAttributeNS(null, 'width', h.toString());
el.setAttributeNS(null, 'height', w.toString());
return el;
}
/**
* Creates a SVG rect.
*/
createSvgPathPlaceholderElement(w, h) {
const el = document.createElementNS(BrowserSvgCodeWriter.SVG_NS, 'path');
el.setAttributeNS(null, 'd', `M0 0h${w}v${h}H0z`);
el.setAttributeNS(null, 'fill', 'none');
return el;
}
/**
* Creates a SVG rect.
*/
createSvgRectElement(x, y, w, h) {
const el = document.createElementNS(BrowserSvgCodeWriter.SVG_NS, 'rect');
el.setAttributeNS(null, 'x', x.toString());
el.setAttributeNS(null, 'y', y.toString());
el.setAttributeNS(null, 'height', w.toString());
el.setAttributeNS(null, 'width', h.toString());
el.setAttributeNS(null, 'fill', '#000000');
return el;
}
}
/**
* Default quiet zone in pixels.
*/
BrowserSvgCodeWriter.QUIET_ZONE_SIZE = 4;
/**
* SVG markup NameSpace
*/
BrowserSvgCodeWriter.SVG_NS = 'http://www.w3.org/2000/svg';
export { BrowserSvgCodeWriter };
@@ -0,0 +1,6 @@
import Exception from '../core/Exception';
import Result from '../core/Result';
/**
* Callback format for continuous decode scan.
*/
export declare type DecodeContinuouslyCallback = (result: Result, error?: Exception) => any;
@@ -0,0 +1,29 @@
import LuminanceSource from '../core/LuminanceSource';
/**
* @deprecated Moving to @zxing/browser
*/
export declare class HTMLCanvasElementLuminanceSource extends LuminanceSource {
private canvas;
private buffer;
private static DEGREE_TO_RADIANS;
private static FRAME_INDEX;
private tempCanvasElement;
constructor(canvas: HTMLCanvasElement, doAutoInvert?: boolean);
private static makeBufferFromCanvasImageData;
private static toGrayscaleBuffer;
getRow(y: number, row: Uint8ClampedArray): Uint8ClampedArray;
getMatrix(): Uint8ClampedArray;
isCropSupported(): boolean;
crop(left: number, top: number, width: number, height: number): LuminanceSource;
/**
* This is always true, since the image is a gray-scale image.
*
* @return true
*/
isRotateSupported(): boolean;
rotateCounterClockwise(): LuminanceSource;
rotateCounterClockwise45(): LuminanceSource;
private getTempCanvasElement;
private rotate;
invert(): LuminanceSource;
}
@@ -0,0 +1,150 @@
import InvertedLuminanceSource from '../core/InvertedLuminanceSource';
import LuminanceSource from '../core/LuminanceSource';
import IllegalArgumentException from '../core/IllegalArgumentException';
/**
* @deprecated Moving to @zxing/browser
*/
export class HTMLCanvasElementLuminanceSource extends LuminanceSource {
constructor(canvas, doAutoInvert = false) {
super(canvas.width, canvas.height);
this.canvas = canvas;
this.tempCanvasElement = null;
this.buffer = HTMLCanvasElementLuminanceSource.makeBufferFromCanvasImageData(canvas, doAutoInvert);
}
static makeBufferFromCanvasImageData(canvas, doAutoInvert = false) {
const imageData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
return HTMLCanvasElementLuminanceSource.toGrayscaleBuffer(imageData.data, canvas.width, canvas.height, doAutoInvert);
}
static toGrayscaleBuffer(imageBuffer, width, height, doAutoInvert = false) {
const grayscaleBuffer = new Uint8ClampedArray(width * height);
HTMLCanvasElementLuminanceSource.FRAME_INDEX = !HTMLCanvasElementLuminanceSource.FRAME_INDEX;
if (HTMLCanvasElementLuminanceSource.FRAME_INDEX || !doAutoInvert) {
for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) {
let gray;
const alpha = imageBuffer[i + 3];
// The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent
// black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a
// barcode image. Force any such pixel to be white:
if (alpha === 0) {
gray = 0xFF;
}
else {
const pixelR = imageBuffer[i];
const pixelG = imageBuffer[i + 1];
const pixelB = imageBuffer[i + 2];
// .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC),
// (306*R) >> 10 is approximately equal to R*0.299, and so on.
// 0x200 >> 10 is 0.5, it implements rounding.
gray = (306 * pixelR +
601 * pixelG +
117 * pixelB +
0x200) >> 10;
}
grayscaleBuffer[j] = gray;
}
}
else {
for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) {
let gray;
const alpha = imageBuffer[i + 3];
// The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent
// black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a
// barcode image. Force any such pixel to be white:
if (alpha === 0) {
gray = 0xFF;
}
else {
const pixelR = imageBuffer[i];
const pixelG = imageBuffer[i + 1];
const pixelB = imageBuffer[i + 2];
// .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC),
// (306*R) >> 10 is approximately equal to R*0.299, and so on.
// 0x200 >> 10 is 0.5, it implements rounding.
gray = (306 * pixelR +
601 * pixelG +
117 * pixelB +
0x200) >> 10;
}
grayscaleBuffer[j] = 0xFF - gray;
}
}
return grayscaleBuffer;
}
getRow(y /*int*/, row) {
if (y < 0 || y >= this.getHeight()) {
throw new IllegalArgumentException('Requested row is outside the image: ' + y);
}
const width = this.getWidth();
const start = y * width;
if (row === null) {
row = this.buffer.slice(start, start + width);
}
else {
if (row.length < width) {
row = new Uint8ClampedArray(width);
}
// The underlying raster of image consists of bytes with the luminance values
// TODO: can avoid set/slice?
row.set(this.buffer.slice(start, start + width));
}
return row;
}
getMatrix() {
return this.buffer;
}
isCropSupported() {
return true;
}
crop(left /*int*/, top /*int*/, width /*int*/, height /*int*/) {
super.crop(left, top, width, height);
return this;
}
/**
* This is always true, since the image is a gray-scale image.
*
* @return true
*/
isRotateSupported() {
return true;
}
rotateCounterClockwise() {
this.rotate(-90);
return this;
}
rotateCounterClockwise45() {
this.rotate(-45);
return this;
}
getTempCanvasElement() {
if (null === this.tempCanvasElement) {
const tempCanvasElement = this.canvas.ownerDocument.createElement('canvas');
tempCanvasElement.width = this.canvas.width;
tempCanvasElement.height = this.canvas.height;
this.tempCanvasElement = tempCanvasElement;
}
return this.tempCanvasElement;
}
rotate(angle) {
const tempCanvasElement = this.getTempCanvasElement();
const tempContext = tempCanvasElement.getContext('2d');
const angleRadians = angle * HTMLCanvasElementLuminanceSource.DEGREE_TO_RADIANS;
// Calculate and set new dimensions for temp canvas
const width = this.canvas.width;
const height = this.canvas.height;
const newWidth = Math.ceil(Math.abs(Math.cos(angleRadians)) * width + Math.abs(Math.sin(angleRadians)) * height);
const newHeight = Math.ceil(Math.abs(Math.sin(angleRadians)) * width + Math.abs(Math.cos(angleRadians)) * height);
tempCanvasElement.width = newWidth;
tempCanvasElement.height = newHeight;
// Draw at center of temp canvas to prevent clipping of image data
tempContext.translate(newWidth / 2, newHeight / 2);
tempContext.rotate(angleRadians);
tempContext.drawImage(this.canvas, width / -2, height / -2);
this.buffer = HTMLCanvasElementLuminanceSource.makeBufferFromCanvasImageData(tempCanvasElement);
return this;
}
invert() {
return new InvertedLuminanceSource(this);
}
}
HTMLCanvasElementLuminanceSource.DEGREE_TO_RADIANS = Math.PI / 180;
HTMLCanvasElementLuminanceSource.FRAME_INDEX = true;
@@ -0,0 +1,4 @@
/**
* HTML elements that can be decoded.
*/
export declare type HTMLVisualMediaElement = HTMLVideoElement | HTMLImageElement;
+27
View File
@@ -0,0 +1,27 @@
/**
* @deprecated Moving to @zxing/browser
*
* Video input device metadata containing the id and label of the device if available.
*/
export declare class VideoInputDevice implements MediaDeviceInfo {
deviceId: string;
label: string;
/** @inheritdoc */
readonly kind = "videoinput";
/** @inheritdoc */
readonly groupId: string;
/**
* Creates an instance of VideoInputDevice.
*
* @param {string} deviceId the video input device id
* @param {string} label the label of the device if available
*/
constructor(deviceId: string, label: string, groupId?: string);
/** @inheritdoc */
toJSON(): {
kind: string;
groupId: string;
deviceId: string;
label: string;
};
}
+29
View File
@@ -0,0 +1,29 @@
/**
* @deprecated Moving to @zxing/browser
*
* Video input device metadata containing the id and label of the device if available.
*/
export class VideoInputDevice {
/**
* Creates an instance of VideoInputDevice.
*
* @param {string} deviceId the video input device id
* @param {string} label the label of the device if available
*/
constructor(deviceId, label, groupId) {
this.deviceId = deviceId;
this.label = label;
/** @inheritdoc */
this.kind = 'videoinput';
this.groupId = groupId || undefined;
}
/** @inheritdoc */
toJSON() {
return {
kind: this.kind,
groupId: this.groupId,
deviceId: this.deviceId,
label: this.label,
};
}
}