/**
* Copyright (c) Microblink Ltd. All rights reserved.
*/
import {
Component,
Element,
Event,
EventEmitter,
Host,
h,
Prop,
Method
} from '@stencil/core';
import {
EventReady,
EventScanError,
EventScanSuccess,
FeedbackMessage,
MicroblinkUI,
SDKError,
ProductIntegrationInfo,
CameraExperienceTimeoutDurations
} from '../../utils/data-structures';
import { SdkService } from '../../utils/sdk.service';
import { TranslationService } from '../../utils/translation.service';
import * as GenericHelpers from '../../utils/generic.helpers';
@Component({
tag: 'blinkid-imagecapture-in-browser',
styleUrl: 'blinkid-imagecapture-in-browser.scss',
shadow: true,
})
export class BlinkidImageCaptureInBrowser implements MicroblinkUI {
private blocked: boolean = false;
/**
* Write a hello message to the browser console when license check is successfully performed.
*
* Hello message will contain the name and version of the SDK, which are required information for all support
* tickets.
*
* Default value is true.
*/
@Prop() allowHelloMessage: boolean = true;
/**
* Absolute location of WASM and related JS/data files. Useful when resource files should be loaded over CDN, or
* when web frameworks/libraries are used which store resources in specific locations, e.g. inside "assets" folder.
*
* Important: if engine is hosted on another origin, CORS must be enabled between two hosts. That is, server where
* engine is hosted must have 'Access-Control-Allow-Origin' header for the location of the web app.
*
* Important: SDK and WASM resources must be from the same version of package.
*
* Default value is empty string, i.e. "". In case of empty string, value of "window.location.origin" property is
* going to be used.
*/
@Prop() engineLocation: string = '';
/**
* The absolute location of the Web Worker script file that loads the WebAssembly module.
*
* Important: the worker script must be served via HTTPS and must be of the same origin as the initiator.
* See https://github.com/w3c/ServiceWorker/issues/940 (same applies for Web Workers).
*
* Important: SDK, worker script and WebAssembly resources must be from the same version of the package.
*
* The default value is an empty string, i.e. "", and in that case, the worker script is loaded from the default location in resources folder.
*/
@Prop() workerLocation: string = '';
/**
* License key which is going to be used to unlock WASM library.
*
* Keep in mind that UI component will reinitialize every time license key is changed.
*/
@Prop() licenseKey: string;
/**
* Defines the type of the WebAssembly build that will be loaded. If omitted, SDK will determine
* the best possible WebAssembly build which should be loaded based on the browser support.
*
* Available WebAssembly builds:
*
* - 'BASIC'
* - 'ADVANCED'
* - 'ADVANCED_WITH_THREADS'
*
* For more information about different WebAssembly builds, check out the `src/MicroblinkSDK/WasmType.ts` file.
*/
@Prop() wasmType: string = '';
/**
* List of recognizers which should be used.
*
* Available recognizers for BlinkID ImageCapture:
*
* - BlinkIdImageCaptureRecognizer
*
* Recognizers can be defined by setting HTML attribute "recognizers", for example:
*
* ``
*/
@Prop({ attribute: 'recognizers' }) rawRecognizers: string;
/**
* List of recognizers which should be used.
*
* Available recognizers for BlinkID ImageCapture:
*
* - BlinkIdImageCaptureRecognizer
*
* Recognizers can be defined by setting JS property "recognizers", for example:
*
* ```
* const blinkId = document.querySelector('blinkid-imagecapture-in-browser');
* blinkId.recognizers = ['BlinkIdImageCaptureRecognizer'];
* ```
*/
@Prop() recognizers: Array;
/**
* Specify recognizer options. This option can only bet set as a JavaScript property.
*
* Pass an object to `recognizerOptions` property where each key represents a recognizer, while
* the value represents desired recognizer options.
*
* ```
* blinkId.recognizerOptions = {
* 'BlinkIdImageCaptureRecognizer': {
* // Enable scanning of both document sides
* 'captureBothDocumentSides': true,
*
* // Scan images of documents that have already been cropped and don't require detection
* 'scanCroppedDocumentImage': true
* }
* }
* ```
*
* For a full list of available recognizer options see source code of a recognizer. For example,
* list of available recognizer options for BlinkIdImageCaptureRecognizer can be seen in the
* `src/Recognizers/BlinkID/ImageCapture/ImageCaptureRecognizer.ts` file.
*/
@Prop() recognizerOptions: { [key: string]: any };
/**
* Amount of time in milliseconds before the recognition process is cancelled regardless of
* whether recognition was successful or not.
*
* This setting applies only to video recognition.
*
* Keep in mind that the timer starts after the first non-empty result. This behaviour ensures
* that the user has enough time to take out the document and place it in front of the camera
* device.
*/
@Prop() recognitionTimeout: number;
/**
* Amount of time in milliseconds before the recognition process is resumed after it is being paused previously.
*
* This setting applies only to video recognition.
*
* Keep in mind that the timer starts after the front side was scanned. This behaviour ensures
* that the user has enough time to flip the document and place its back side in front of the camera
* device.
*/
@Prop() recognitionPauseTimeout: number = 3800;
/**
* Configure camera experience state timeout durations
*/
@Prop() cameraExperienceStateDurations: CameraExperienceTimeoutDurations = null;
/**
* Set to 'false' if component should not enable drag and drop functionality.
*
* Default value is 'true'.
*/
@Prop() enableDrag: boolean = true;
/**
* If set to 'true', UI component will not display feedback, i.e. information and error messages.
*
* Setting this attribute to 'false' won't disable 'scanError' and 'scanInfo' events.
*
* Default value is 'false'.
*/
@Prop() hideFeedback: boolean = false;
/**
* If set to 'true', UI component will become visible after successful SDK initialization. Also, error screen
* is not going to be displayed in case of initialization error.
*
* If set to 'false', loading and error screens of the UI component will be visible during initialization and in case
* of an error.
*
* Default value is 'false'.
*/
@Prop() hideLoadingAndErrorUi: boolean = false;
/**
* Set to 'true' if scan from camera should be enabled. If set to 'true' and camera is not available or disabled,
* related button will be visible but disabled.
*
* Default value is 'true'.
*/
@Prop() scanFromCamera: boolean = true;
/**
* Set to 'true' if scan from image should be enabled.
*
* Default value is 'true'.
*/
@Prop() scanFromImage: boolean = true;
/**
* Set to 'true' if scan from image should execute twice in case that first result is empty.
*
* If enabled, this option will add/remove 'scanCroppedDocumentImage' recognizer option for the
* second scan action.
*/
@Prop() thoroughScanFromImage: boolean = false;
/**
* Define whether to use 'FULLSCREEN' or 'INLINE' gallery overlay type.
*
* If 'FULLSCREEN' is used, when a user selects an image from which data should be extracted, an overlay will pop up
* and cover the whole screen.
*
* On the other hand, if 'INLINE' is used, there is no overlay but rather a 'Processing' message inside the UI
* component.
*
* Default value is 'INLINE'.
*/
@Prop() galleryOverlayType: 'FULLSCREEN' | 'INLINE' = 'INLINE';
/**
* Define whether to use 'FULLSCREEN' or 'INLINE' gallery dropdown type.
*
* If 'FULLSCREEN' is used, when a user drags an image over the UI component, an overlay will pop up and cover the
* whole screen.
*
* If 'INLINE' is used, there is no fullscreen overlay, but rather the overlay is restricted to the size of the UI
* component.
*
* Default value is 'INLINE'.
*/
@Prop() galleryDropType: 'FULLSCREEN' | 'INLINE' = 'INLINE';
/**
* Set to 'true' if text labels should be displayed below action buttons.
*
* Default value is 'false'.
*/
@Prop() showActionLabels: boolean = false;
/**
* Set to 'true' if modal window should be displayed in case of an error.
*
* Default value is 'false'.
*/
@Prop() showModalWindows: boolean = false;
/**
* Set custom translations for UI component. List of available translation keys can be found in
* `src/utils/translation.service.ts` file.
*/
@Prop({ attribute: 'translations' }) rawTranslations: string;
/**
* Set custom translations for UI component. List of available translation keys can be found in
* `src/utils/translation.service.ts` file.
*/
@Prop() translations: { [key: string]: string };
/**
* Provide alternative camera icon.
*
* Every value that is placed here is passed as a value of `src` attribute to
element. This attribute can be
* used to provide location, base64 or any URL of alternative camera icon.
*
* Image is scaled to 20x20 pixels.
*/
@Prop() iconCameraDefault: string;
/**
* Hover state of iconCameraDefault.
*/
@Prop() iconCameraActive: string;
/**
* Provide alternative gallery icon. This icon is also used during drag and drop action.
*
* Every value that is placed here is passed as a value of `src` attribute to
element. This attribute can be
* used to provide location, base64 or any URL of alternative gallery icon.
*
* Image is scaled to 20x20 pixels. In drag and drop dialog image is scaled to 24x24 pixels.
*/
@Prop() iconGalleryDefault: string;
/**
* Hover state of iconGalleryDefault.
*/
@Prop() iconGalleryActive: string;
/**
* Provide alternative invalid format icon which is used during drag and drop action.
*
* Every value that is placed here is passed as a value of `src` attribute to
element. This attribute can be
* used to provide location, base64 or any URL of alternative icon.
*
* Image is scaled to 24x24 pixels.
*/
@Prop() iconInvalidFormat: string;
/**
* Provide alternative loading icon. CSS rotation is applied to this icon.
*
* Every value that is placed here is passed as a value of `src` attribute to
element. This attribute can be
* used to provide location, base64 or any URL of alternative icon.
*
* Image is scaled to 24x24 pixels.
*/
@Prop() iconSpinnerScreenLoading: string;
/**
* Provide alternative loading icon. CSS rotation is applied to this icon.
*
* Every value that is placed here is passed as a value of `src` attribute to
element. This attribute can be
* used to provide location, base64 or any URL of alternative icon.
*
* Image is scaled to 24x24 pixels.
*/
@Prop() iconSpinnerFromGalleryExperience: string;
/**
* Provide alternative completed icon. This icon is used when gallery scanning process is done, in case that
* `galleryOverlayType` property is set to `INLINE`.
*
* Every value that is placed here is passed as a value of `src` attribute to
element. This attribute can be
* used to provide location, base64 or any URL of alternative icon.
*
* Image is scaled to 24x24 pixels.
*/
@Prop() iconGalleryScanningCompleted: string;
/**
* Camera device ID passed from root component.
*
* Client can choose which camera to turn on if array of cameras exists.
*
*/
@Prop() cameraId: string | null = null;
/**
* Event which is emitted during initialization of UI component.
*
* Each event contains `code` property which has deatils about fatal errror.
*/
@Event() fatalError: EventEmitter;
/**
* Event which is emitted when UI component is successfully initialized and ready for use.
*/
@Event() ready: EventEmitter;
/**
* Event which is emitted during or immediately after scan error.
*/
@Event() scanError: EventEmitter;
/**
* Event which is emitted after successful scan. This event contains recognition results.
*/
@Event() scanSuccess: EventEmitter;
/**
* Event which is emitted during positive or negative user feedback. If attribute/property
* `hideFeedback` is set to `false`, UI component will display the feedback.
*/
@Event() feedback: EventEmitter;
/**
* Event which is emitted when camera scan is started, i.e. when user clicks on
* _scan from camera_ button.
*/
@Event() cameraScanStarted: EventEmitter;
/**
* Event which is emitted when image scan is started, i.e. when user clicks on
* _scan from gallery button.
*/
@Event() imageScanStarted: EventEmitter;
/**
* Event which is emitted when scan is aborted, i.e. when user clicks on
* close from the gallery toolbar, or presses escape key.
*/
@Event() scanAborted: EventEmitter;
/**
* Control UI state of camera overlay.
*
* Possible values are 'ERROR' | 'LOADING' | 'NONE' | 'SUCCESS'.
*
* In case of state `ERROR` and if `showModalWindows` is set to `true`, modal window
* with error message will be displayed. Otherwise, UI will close.
*/
@Method()
async setUiState(state: 'ERROR' | 'LOADING' | 'NONE' | 'SUCCESS') {
this.mbComponentEl.setUiState(state);
}
/**
* Starts camera scan using camera overlay with usage instructions.
*/
@Method()
async startCameraScan() {
this.mbComponentEl.startCameraScan();
}
/**
* Starts image scan, emits results from provided file.
*
* @param file File to scan
*/
@Method()
async startImageScan(file: File) {
this.mbComponentEl.startImageScan(file);
}
/**
* Starts multi-side image scan, emits results from provided files.
*
* @param firstFile File to scan as first image
* @param secondFile File to scan as second image
*/
@Method()
async startMultiSideImageScan(firstFile: File, secondFile: File) {
this.mbComponentEl.startMultiSideImageScan(firstFile, secondFile);
}
/**
* Show message alongside UI component.
*
* Possible values for `state` are 'FEEDBACK_ERROR' | 'FEEDBACK_INFO' | 'FEEDBACK_OK'.
*/
@Method()
async setUiMessage(state: 'FEEDBACK_ERROR' | 'FEEDBACK_INFO' | 'FEEDBACK_OK', message: string) {
this.feedbackEl.show({ state, message });
}
/**
* Get information about product integration.
*/
@Method()
async getProductIntegrationInfo(): Promise {
return this.sdkService?.getProductIntegrationInfo();
}
@Element() hostEl: HTMLElement;
componentWillLoad() {
this.init();
}
componentWillUpdate() {
if (this.blocked) {
return;
}
this.sdkService?.delete();
this.init();
}
disconnectedCallback() {
this.sdkService?.delete();
}
private init() {
const rawRecognizers = GenericHelpers.stringToArray(this.rawRecognizers);
this.finalRecognizers = this.recognizers ? this.recognizers : rawRecognizers;
const rawTranslations = GenericHelpers.stringToObject(this.rawTranslations);
this.finalTranslations = this.translations ? this.translations : rawTranslations;
this.translationService = new TranslationService(this.finalTranslations || {});
this.sdkService = new SdkService();
}
render() {
return (
this.mbComponentEl = el as HTMLMbComponentElement }
allowHelloMessage={ this.allowHelloMessage }
recognitionPauseTimeout={ this.recognitionPauseTimeout }
cameraExperienceStateDurations={ this.cameraExperienceStateDurations }
engineLocation={ this.engineLocation }
workerLocation={ this.workerLocation }
licenseKey={ this.licenseKey }
wasmType={ this.wasmType }
recognizers={ this.finalRecognizers }
recognizerOptions={ this.recognizerOptions }
recognitionTimeout={ this.recognitionTimeout }
enableDrag={ this.enableDrag }
hideLoadingAndErrorUi={ this.hideLoadingAndErrorUi }
scanFromCamera={ this.scanFromCamera }
scanFromImage={ this.scanFromImage }
thoroughScanFromImage={ this.thoroughScanFromImage }
galleryOverlayType={ this.galleryOverlayType }
galleryDropType={ this.galleryDropType }
showActionLabels={ this.showActionLabels }
showModalWindows={ this.showModalWindows }
iconCameraDefault={ this.iconCameraDefault}
iconCameraActive={ this.iconCameraActive }
iconGalleryDefault={ this.iconGalleryDefault }
iconGalleryActive={ this.iconGalleryActive }
iconInvalidFormat={ this.iconInvalidFormat }
iconSpinnerScreenLoading={ this.iconSpinnerScreenLoading }
iconSpinnerFromGalleryExperience={ this.iconSpinnerFromGalleryExperience }
iconGalleryScanningCompleted={ this.iconGalleryScanningCompleted }
sdkService={ this.sdkService }
translationService={ this.translationService }
cameraId={ this.cameraId }
onBlock={ (ev: CustomEvent) => { this.blocked = ev.detail } }
onFeedback={ (ev: CustomEvent) => this.feedbackEl.show(ev.detail) }>
this.feedbackEl = el as HTMLMbFeedbackElement }>
);
}
private sdkService: SdkService;
private translationService: TranslationService;
private finalRecognizers: Array;
private finalTranslations: { [key: string]: string };
private feedbackEl!: HTMLMbFeedbackElement;
private mbComponentEl!: HTMLMbComponentElement;
}