UNPKG

scandit-sdk

Version:

Scandit Barcode Scanner SDK for the Web

733 lines (638 loc) 28.7 kB
import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer"; // tslint:disable-next-line: variable-name const ResizeObserver: typeof ResizeObserverPolyfill = // tslint:disable-next-line: no-any "ResizeObserver" in window ? /* istanbul ignore next */ (<any>window).ResizeObserver : ResizeObserverPolyfill; import { cameraImage, laserActiveImage, laserPausedImage, scanditLogoImage, switchCameraImage, toggleTorchImage } from "./assets/base64assets"; import { BarcodePicker } from "./barcodePicker"; import { BrowserHelper } from "./browserHelper"; import { Camera } from "./camera"; import { CameraAccess } from "./cameraAccess"; import { CameraManager } from "./cameraManager"; import { ImageSettings } from "./imageSettings"; import { Scanner } from "./scanner"; import { ScanSettings } from "./scanSettings"; import { SearchArea } from "./searchArea"; /** * @hidden */ export class BarcodePickerGui { public static readonly grandParentElementClassName: string = "scandit scandit-container"; public static readonly parentElementClassName: string = "scandit scandit-barcode-picker"; public static readonly hiddenClassName: string = "scandit-hidden"; public static readonly hiddenOpacityClassName: string = "scandit-hidden-opacity"; public static readonly videoElementClassName: string = "scandit-video"; public static readonly scanditLogoImageElementClassName: string = "scandit-logo"; public static readonly laserContainerElementClassName: string = "scandit-laser"; public static readonly viewfinderElementClassName: string = "scandit-viewfinder"; public static readonly cameraSwitcherElementClassName: string = "scandit-camera-switcher"; public static readonly torchTogglerElementClassName: string = "scandit-torch-toggle"; public static readonly cameraUploadElementClassName: string = "scandit-camera-upload"; public static readonly flashColorClassName: string = "scandit-flash-color"; public static readonly flashWhiteClassName: string = "scandit-flash-white"; public static readonly flashWhiteInsetClassName: string = "scandit-flash-white-inset"; public static readonly opacityPulseClassName: string = "scandit-opacity-pulse"; public static readonly mirroredClassName: string = "mirrored"; public static readonly pausedClassName: string = "paused"; public readonly videoElement: HTMLVideoElement; public readonly cameraSwitcherElement: HTMLImageElement; public readonly torchTogglerElement: HTMLImageElement; private readonly scanner: Scanner; private readonly singleImageMode: boolean; private readonly grandParentElement: HTMLDivElement; private readonly parentElement: HTMLDivElement; private readonly laserContainerElement: HTMLDivElement; private readonly laserActiveImageElement: HTMLImageElement; private readonly laserPausedImageElement: HTMLImageElement; private readonly viewfinderElement: HTMLDivElement; private readonly cameraUploadElement: HTMLDivElement; private readonly cameraUploadInputElement: HTMLInputElement; private readonly cameraUploadLabelElement: HTMLLabelElement; private readonly cameraUploadProgressElement: HTMLDivElement; private readonly videoImageCanvasContext: CanvasRenderingContext2D; private readonly visibilityListener: EventListenerOrEventListenerObject; private readonly videoResizeListener: EventListenerOrEventListenerObject; private readonly newScanSettingsListener: (scanSettings: ScanSettings) => void; private readonly licenseFeaturesReadyListener: (licenseFeatures: object) => void; private readonly resizeObserver: ResizeObserverPolyfill; private readonly cameraUploadCallback: () => Promise<void>; private readonly mirrorImageOverrides: Map<string, boolean>; private cameraManager?: CameraManager; private originElement: HTMLElement; private scanningPaused: boolean; private visible: boolean; private guiStyle: BarcodePicker.GuiStyle; private videoFit: BarcodePicker.ObjectFit; private customLaserArea?: SearchArea; private customViewfinderArea?: SearchArea; public constructor(options: { scanner: Scanner; originElement: HTMLElement; singleImageMode: boolean; scanningPaused: boolean; visible: boolean; guiStyle: BarcodePicker.GuiStyle; videoFit: BarcodePicker.ObjectFit; hideLogo: boolean; laserArea?: SearchArea; viewfinderArea?: SearchArea; cameraUploadCallback(): Promise<void>; }) { this.scanner = options.scanner; this.originElement = options.originElement; this.singleImageMode = options.singleImageMode; this.scanningPaused = options.scanningPaused; this.cameraUploadCallback = options.cameraUploadCallback; this.mirrorImageOverrides = new Map<string, boolean>(); this.grandParentElement = document.createElement("div"); this.grandParentElement.className = BarcodePickerGui.grandParentElementClassName; this.originElement.appendChild(this.grandParentElement); this.parentElement = document.createElement("div"); this.parentElement.className = BarcodePickerGui.parentElementClassName; this.grandParentElement.appendChild(this.parentElement); this.videoImageCanvasContext = <CanvasRenderingContext2D>document.createElement("canvas").getContext("2d"); this.videoElement = document.createElement("video"); this.cameraSwitcherElement = document.createElement("img"); this.torchTogglerElement = document.createElement("img"); this.laserContainerElement = document.createElement("div"); this.laserActiveImageElement = document.createElement("img"); this.laserPausedImageElement = document.createElement("img"); this.viewfinderElement = document.createElement("div"); if (options.singleImageMode) { this.cameraUploadElement = document.createElement("div"); this.cameraUploadInputElement = document.createElement("input"); this.cameraUploadLabelElement = document.createElement("label"); this.cameraUploadProgressElement = document.createElement("div"); this.setupCameraUploadGuiAssets(); this.guiStyle = BarcodePicker.GuiStyle.NONE; } else { this.setupVideoElement(); this.setupCameraSwitcher(); this.setupTorchToggler(); this.setupFullGuiAssets(); this.setGuiStyle(options.guiStyle); this.setVideoFit(options.videoFit); this.setLaserArea(options.laserArea); this.setViewfinderArea(options.viewfinderArea); this.visibilityListener = this.checkAndRecoverPlayback.bind(this); document.addEventListener("visibilitychange", this.visibilityListener); this.newScanSettingsListener = this.handleNewScanSettings.bind(this); this.scanner.onNewScanSettings(this.newScanSettingsListener); this.handleNewScanSettings(); this.videoResizeListener = this.handleVideoResize.bind(this); this.videoElement.addEventListener("resize", this.videoResizeListener); } if (options.hideLogo) { this.licenseFeaturesReadyListener = this.showScanditLogo.bind(this, options.hideLogo); this.scanner.onLicenseFeaturesReady(this.licenseFeaturesReadyListener); } else { this.showScanditLogo(false); } this.resize(); this.resizeObserver = new ResizeObserver(() => { this.resize(); }); this.resizeObserver.observe(this.originElement); this.setVisible(options.visible); } public destroy(): void { if (this.visibilityListener != null) { document.removeEventListener("visibilitychange", this.visibilityListener); } if (this.newScanSettingsListener != null) { this.scanner.removeListener("newScanSettings", this.newScanSettingsListener); } if (this.videoResizeListener != null) { document.removeEventListener("resize", this.videoResizeListener); } if (this.licenseFeaturesReadyListener != null) { this.scanner.removeListener("licenseFeaturesReady", this.licenseFeaturesReadyListener); } this.resizeObserver.disconnect(); this.grandParentElement.remove(); this.originElement.classList.remove(BarcodePickerGui.hiddenClassName); } public setCameraManager(cameraManager: CameraManager): void { this.cameraManager = cameraManager; } public pauseScanning(): void { this.scanningPaused = true; this.laserActiveImageElement.classList.add(BarcodePickerGui.hiddenOpacityClassName); this.laserPausedImageElement.classList.remove(BarcodePickerGui.hiddenOpacityClassName); this.viewfinderElement.classList.add(BarcodePickerGui.pausedClassName); } public resumeScanning(): void { this.scanningPaused = false; this.laserPausedImageElement.classList.add(BarcodePickerGui.hiddenOpacityClassName); this.laserActiveImageElement.classList.remove(BarcodePickerGui.hiddenOpacityClassName); this.viewfinderElement.classList.remove(BarcodePickerGui.pausedClassName); } public isVisible(): boolean { return this.visible; } public setVisible(visible: boolean): void { const browserName: string | undefined = BrowserHelper.userAgentInfo.getBrowser().name; if (browserName != null && browserName.includes("Safari") && this.visible != null && !this.visible && visible) { // Safari behaves very weirdly when displaying the video element again after being hidden: // it undetectably reuses video frames "buffered" from the video just before it was hidden. // We do this to avoid reusing old data this.videoElement.pause(); this.videoElement.currentTime = 0; this.videoElement.load(); this.playVideo(); } this.visible = visible; if (visible) { this.originElement.classList.remove(BarcodePickerGui.hiddenClassName); if (this.guiStyle === BarcodePicker.GuiStyle.LASER) { this.laserActiveImageElement.classList.remove(BarcodePickerGui.flashColorClassName); } else if (this.guiStyle === BarcodePicker.GuiStyle.VIEWFINDER) { this.viewfinderElement.classList.remove(BarcodePickerGui.flashWhiteClassName); } } else { this.originElement.classList.add(BarcodePickerGui.hiddenClassName); } } public isMirrorImageEnabled(): boolean { if ( this.cameraManager != null && this.cameraManager.selectedCamera != null && this.cameraManager.activeCamera != null ) { const mirrorImageOverride: boolean | undefined = this.mirrorImageOverrides.get( this.cameraManager.activeCamera.deviceId + this.cameraManager.activeCamera.label ); if (mirrorImageOverride != null) { return mirrorImageOverride; } else { return this.cameraManager.activeCamera.cameraType === Camera.Type.FRONT; } } else { return false; } } public setMirrorImageEnabled(enabled: boolean, override: boolean): void { if (this.cameraManager != null && this.cameraManager.selectedCamera != null) { if (enabled) { this.videoElement.classList.add(BarcodePickerGui.mirroredClassName); } else { this.videoElement.classList.remove(BarcodePickerGui.mirroredClassName); } if (override) { this.mirrorImageOverrides.set( this.cameraManager.selectedCamera.deviceId + this.cameraManager.selectedCamera.label, enabled ); } } } public setGuiStyle(guiStyle: BarcodePicker.GuiStyle): void { if (this.singleImageMode) { return; } switch (guiStyle) { case BarcodePicker.GuiStyle.LASER: this.guiStyle = guiStyle; this.laserContainerElement.classList.remove(BarcodePickerGui.hiddenClassName); this.viewfinderElement.classList.add(BarcodePickerGui.hiddenClassName); break; case BarcodePicker.GuiStyle.VIEWFINDER: this.guiStyle = guiStyle; this.laserContainerElement.classList.add(BarcodePickerGui.hiddenClassName); this.viewfinderElement.classList.remove(BarcodePickerGui.hiddenClassName); break; case BarcodePicker.GuiStyle.NONE: default: this.guiStyle = BarcodePicker.GuiStyle.NONE; this.laserContainerElement.classList.add(BarcodePickerGui.hiddenClassName); this.viewfinderElement.classList.add(BarcodePickerGui.hiddenClassName); break; } } public setLaserArea(area?: SearchArea): void { this.customLaserArea = area; if (area == null) { area = this.scanner.getScanSettings().getSearchArea(); } const borderPercentage: number = 0.025; const usablePercentage: number = 1 - borderPercentage * 2; this.laserContainerElement.style.left = `${(borderPercentage + area.x * usablePercentage) * 100}%`; this.laserContainerElement.style.width = `${area.width * usablePercentage * 100}%`; this.laserContainerElement.style.top = `${(borderPercentage + area.y * usablePercentage) * 100}%`; this.laserContainerElement.style.height = `${area.height * usablePercentage * 100}%`; } public setViewfinderArea(area?: SearchArea): void { this.customViewfinderArea = area; if (area == null) { area = this.scanner.getScanSettings().getSearchArea(); } const borderPercentage: number = 0.025; const usablePercentage: number = 1 - borderPercentage * 2; this.viewfinderElement.style.left = `${(borderPercentage + area.x * usablePercentage) * 100}%`; this.viewfinderElement.style.width = `${area.width * usablePercentage * 100}%`; this.viewfinderElement.style.top = `${(borderPercentage + area.y * usablePercentage) * 100}%`; this.viewfinderElement.style.height = `${area.height * usablePercentage * 100}%`; } public setVideoFit(objectFit: BarcodePicker.ObjectFit): void { if (this.singleImageMode) { return; } this.videoFit = objectFit; if (objectFit === BarcodePicker.ObjectFit.COVER) { this.videoElement.style.objectFit = "cover"; this.videoElement.dataset.objectFit = "cover"; // used by "objectFitPolyfill" library } else { this.videoElement.style.objectFit = "contain"; this.videoElement.dataset.objectFit = "contain"; // used by "objectFitPolyfill" library this.scanner.applyScanSettings( this.scanner.getScanSettings().setBaseSearchArea({ x: 0, y: 0, width: 1.0, height: 1.0 }) ); } this.resize(); } public reassignOriginElement(originElement: HTMLElement): void { if (!this.visible) { this.originElement.classList.remove(BarcodePickerGui.hiddenClassName); originElement.classList.add(BarcodePickerGui.hiddenClassName); } originElement.appendChild(this.grandParentElement); this.checkAndRecoverPlayback(); this.resize(); this.resizeObserver.disconnect(); this.resizeObserver.observe(originElement); this.originElement = originElement; } public flashGUI(): void { if (this.guiStyle === BarcodePicker.GuiStyle.LASER) { this.flashLaser(); } else if (this.guiStyle === BarcodePicker.GuiStyle.VIEWFINDER) { this.flashViewfinder(); } } public getVideoImageData(): Uint8ClampedArray | undefined { if (!this.singleImageMode) { // This could happen in very weird situations and should be temporary if ( this.videoElement.readyState !== 4 || this.videoImageCanvasContext.canvas.width <= 2 || this.videoImageCanvasContext.canvas.height <= 2 ) { return undefined; } this.videoImageCanvasContext.drawImage(this.videoElement, 0, 0); } return this.videoImageCanvasContext.getImageData( 0, 0, this.videoImageCanvasContext.canvas.width, this.videoImageCanvasContext.canvas.height ).data; } public getVideoCurrentTime(): number { return this.videoElement.currentTime; } public setCameraSwitcherVisible(visible: boolean): void { if (visible) { this.cameraSwitcherElement.classList.remove(BarcodePickerGui.hiddenClassName); } else { this.cameraSwitcherElement.classList.add(BarcodePickerGui.hiddenClassName); } } public setTorchTogglerVisible(visible: boolean): void { if (visible) { this.torchTogglerElement.classList.remove(BarcodePickerGui.hiddenClassName); } else { this.torchTogglerElement.classList.add(BarcodePickerGui.hiddenClassName); } } public playVideo(): void { const playPromise: Promise<void> = this.videoElement.play(); if (playPromise != null) { playPromise.catch( /* istanbul ignore next */ () => { // Can sometimes cause an incorrect rejection (all is good, ignore). } ); } } private setCameraUploadGuiAvailable(available: boolean): void { if (available) { this.cameraUploadProgressElement.classList.add(BarcodePickerGui.flashWhiteInsetClassName); this.cameraUploadElement.classList.remove(BarcodePickerGui.opacityPulseClassName); } else { this.cameraUploadProgressElement.classList.remove(BarcodePickerGui.flashWhiteInsetClassName); this.cameraUploadElement.classList.add(BarcodePickerGui.opacityPulseClassName); } } private setupVideoElement(): void { this.videoElement.setAttribute("autoplay", "autoplay"); this.videoElement.setAttribute("playsinline", "true"); this.videoElement.setAttribute("muted", "muted"); this.videoElement.className = BarcodePickerGui.videoElementClassName; this.parentElement.appendChild(this.videoElement); } private setupCameraUploadGuiAssets(): void { this.cameraUploadElement.className = BarcodePickerGui.cameraUploadElementClassName; this.parentElement.appendChild(this.cameraUploadElement); this.cameraUploadInputElement.type = "file"; this.cameraUploadInputElement.accept = "image/*"; this.cameraUploadInputElement.setAttribute("capture", "environment"); this.cameraUploadInputElement.addEventListener("change", this.cameraUploadFile.bind(this)); this.cameraUploadInputElement.addEventListener( "click", /* istanbul ignore next */ event => { if (this.scanningPaused || this.scanner.isBusyProcessing()) { event.preventDefault(); } } ); this.cameraUploadLabelElement.appendChild(this.cameraUploadInputElement); this.cameraUploadElement.appendChild(this.cameraUploadLabelElement); const cameraUploadImageElement: HTMLImageElement = document.createElement("img"); cameraUploadImageElement.src = cameraImage; this.cameraUploadLabelElement.appendChild(cameraUploadImageElement); const cameraUploadTextElement: HTMLDivElement = document.createElement("div"); cameraUploadTextElement.innerText = "Scan from Camera"; this.cameraUploadLabelElement.appendChild(cameraUploadTextElement); this.cameraUploadProgressElement.classList.add("radial-progress"); this.cameraUploadElement.appendChild(this.cameraUploadProgressElement); } private setupFullGuiAssets(): void { this.laserActiveImageElement.src = laserActiveImage; this.laserContainerElement.appendChild(this.laserActiveImageElement); this.laserPausedImageElement.src = laserPausedImage; this.laserContainerElement.appendChild(this.laserPausedImageElement); this.laserContainerElement.className = BarcodePickerGui.laserContainerElementClassName; this.parentElement.appendChild(this.laserContainerElement); this.viewfinderElement.className = BarcodePickerGui.viewfinderElementClassName; this.parentElement.appendChild(this.viewfinderElement); // Show inactive GUI, as for now the scanner isn't ready yet this.laserActiveImageElement.classList.add(BarcodePickerGui.hiddenOpacityClassName); this.laserPausedImageElement.classList.remove(BarcodePickerGui.hiddenOpacityClassName); this.viewfinderElement.classList.add(BarcodePickerGui.pausedClassName); } private flashLaser(): void { this.laserActiveImageElement.classList.remove(BarcodePickerGui.flashColorClassName); // tslint:disable-next-line:no-unused-expression this.laserActiveImageElement.offsetHeight; // NOSONAR // Trigger reflow to restart animation this.laserActiveImageElement.classList.add(BarcodePickerGui.flashColorClassName); } private flashViewfinder(): void { this.viewfinderElement.classList.remove(BarcodePickerGui.flashWhiteClassName); // tslint:disable-next-line:no-unused-expression this.viewfinderElement.offsetHeight; // NOSONAR // Trigger reflow to restart animation this.viewfinderElement.classList.add(BarcodePickerGui.flashWhiteClassName); } private resize(): void { if (this.singleImageMode) { this.resizeCameraUpload(); } else { this.resizeVideo(); } } private resizeCameraUpload(): void { const width: number = this.originElement.clientWidth; const height: number = this.originElement.clientHeight; this.cameraUploadLabelElement.style.transform = `scale(${Math.min(1, width / 500, height / 300)})`; this.cameraUploadProgressElement.style.transform = `scale(${Math.min(1, width / 500, height / 300)})`; } private resizeVideo(): void { if (this.videoElement.videoWidth <= 2 || this.videoElement.videoHeight <= 2) { return; } this.parentElement.style.maxWidth = null; this.parentElement.style.maxHeight = null; let width: number = this.originElement.clientWidth; let height: number = this.originElement.clientHeight; const videoRatio: number = this.videoElement.videoWidth / this.videoElement.videoHeight; if (this.videoFit === BarcodePicker.ObjectFit.COVER) { let widthPercentage: number = 1; let heightPercentage: number = 1; if (videoRatio < width / height) { heightPercentage = Math.min(1, height / (width / videoRatio)); } else { widthPercentage = Math.min(1, width / (height * videoRatio)); } this.scanner.applyScanSettings( this.scanner.getScanSettings().setBaseSearchArea({ x: (1 - widthPercentage) / 2, y: (1 - heightPercentage) / 2, width: widthPercentage, height: heightPercentage }) ); return; } if (videoRatio > width / height) { height = width / videoRatio; } else { width = height * videoRatio; } this.parentElement.style.maxWidth = `${Math.ceil(width)}px`; this.parentElement.style.maxHeight = `${Math.ceil(height)}px`; window.objectFitPolyfill(this.videoElement); } private checkAndRecoverPlayback(): void { if ( this.cameraManager != null && this.cameraManager.activeCamera != null && this.videoElement != null && this.videoElement.srcObject != null ) { if (!(<MediaStream>this.videoElement.srcObject).active) { this.cameraManager.reinitializeCamera(); } else { this.playVideo(); } } } private updateCameraUploadProgress(progressPercentageValue: string): void { this.cameraUploadProgressElement.setAttribute("data-progress", progressPercentageValue); } private async cameraUploadImageLoad(image: HTMLImageElement): Promise<void> { this.updateCameraUploadProgress("100"); let resizedImageWidth: number; let resizedImageHeight: number; const resizedImageSizeLimit: number = 1440; if (image.naturalWidth <= resizedImageSizeLimit && image.naturalHeight <= resizedImageSizeLimit) { resizedImageWidth = image.naturalWidth; resizedImageHeight = image.naturalHeight; } else { if (image.naturalWidth > image.naturalHeight) { resizedImageWidth = resizedImageSizeLimit; resizedImageHeight = Math.round((image.naturalHeight / image.naturalWidth) * resizedImageSizeLimit); } else { resizedImageWidth = Math.round((image.naturalWidth / image.naturalHeight) * resizedImageSizeLimit); resizedImageHeight = resizedImageSizeLimit; } } await this.cameraUploadFileProcess(image, resizedImageWidth, resizedImageHeight); } private async cameraUploadFileProcess(image: HTMLImageElement, width: number, height: number): Promise<void> { this.videoImageCanvasContext.canvas.width = width; this.videoImageCanvasContext.canvas.height = height; this.videoImageCanvasContext.drawImage(image, 0, 0, width, height); this.scanner.applyImageSettings({ width, height, format: ImageSettings.Format.RGBA_8U }); this.setCameraUploadGuiAvailable(false); await this.cameraUploadCallback(); this.setCameraUploadGuiAvailable(true); } private cameraUploadFile(): void { const files: FileList | null = this.cameraUploadInputElement.files; if (files != null && files.length !== 0) { const image: HTMLImageElement = new Image(); const fileReader: FileReader = new FileReader(); fileReader.onload = () => { this.cameraUploadInputElement.value = ""; if (fileReader.result != null) { image.onload = this.cameraUploadImageLoad.bind(this, image); image.onprogress = event2 => { if (event2.lengthComputable) { const progress: number = Math.round((event2.loaded / event2.total) * 20) * 5; if (progress <= 100) { this.updateCameraUploadProgress(progress.toString()); } } }; image.src = <string>fileReader.result; } }; this.updateCameraUploadProgress("0"); fileReader.readAsDataURL(files[0]); } } private setupCameraSwitcher(): void { this.cameraSwitcherElement.src = switchCameraImage; this.cameraSwitcherElement.className = BarcodePickerGui.cameraSwitcherElementClassName; this.cameraSwitcherElement.classList.add(BarcodePickerGui.hiddenClassName); this.parentElement.appendChild(this.cameraSwitcherElement); ["touchstart", "mousedown"].forEach(eventName => { this.cameraSwitcherElement.addEventListener(eventName, async event => { if (this.cameraManager != null) { const cameraManager: CameraManager = this.cameraManager; event.preventDefault(); try { const cameras: Camera[] = await CameraAccess.getCameras(); const newCameraIndex: number = (cameras.findIndex(camera => { return ( camera.deviceId === (cameraManager.activeCamera == null ? camera.deviceId : cameraManager.activeCamera.deviceId) ); }) + 1) % cameras.length; cameraManager .initializeCameraWithSettings(cameras[newCameraIndex], cameraManager.activeCameraSettings) .catch(console.error); } catch (error) { console.error(error); } } }); }); } private setupTorchToggler(): void { this.torchTogglerElement.src = toggleTorchImage; this.torchTogglerElement.className = BarcodePickerGui.torchTogglerElementClassName; this.torchTogglerElement.classList.add(BarcodePickerGui.hiddenClassName); this.parentElement.appendChild(this.torchTogglerElement); ["touchstart", "mousedown"].forEach(eventName => { this.torchTogglerElement.addEventListener(eventName, event => { if (this.cameraManager != null) { event.preventDefault(); this.cameraManager.toggleTorch(); } }); }); } private showScanditLogo(hideLogo: boolean, licenseFeatures?: { hiddenScanditLogoAllowed?: boolean }): void { if ( hideLogo && licenseFeatures != null && licenseFeatures.hiddenScanditLogoAllowed != null && licenseFeatures.hiddenScanditLogoAllowed ) { return; } const scanditLogoImageElement: HTMLImageElement = document.createElement("img"); scanditLogoImageElement.src = scanditLogoImage; scanditLogoImageElement.className = BarcodePickerGui.scanditLogoImageElementClassName; this.parentElement.appendChild(scanditLogoImageElement); } private handleNewScanSettings(): void { if (this.customLaserArea == null) { this.setLaserArea(); } if (this.customViewfinderArea == null) { this.setViewfinderArea(); } } private handleVideoResize(): void { if ( this.videoImageCanvasContext.canvas.width === this.videoElement.videoWidth && this.videoImageCanvasContext.canvas.height === this.videoElement.videoHeight ) { return; } this.videoImageCanvasContext.canvas.width = this.videoElement.videoWidth; this.videoImageCanvasContext.canvas.height = this.videoElement.videoHeight; this.scanner.applyImageSettings({ width: this.videoElement.videoWidth, height: this.videoElement.videoHeight, format: ImageSettings.Format.RGBA_8U }); this.resize(); } }