UNPKG

ngx-webcam

Version:

A simple Angular webcam component. Pure &amp; minimal, no Flash-fallback. <a href="https://basst314.github.io/ngx-webcam/?" target="_blank">See the Demo!</a>

516 lines (507 loc) 27.5 kB
import * as i0 from '@angular/core'; import { EventEmitter, Component, Input, Output, ViewChild, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; /** * Container class for a captured webcam image * @author basst314, davidshen84 */ class WebcamImage { constructor(imageAsDataUrl, mimeType, imageData) { this._mimeType = null; this._imageAsBase64 = null; this._imageAsDataUrl = null; this._imageData = null; this._mimeType = mimeType; this._imageAsDataUrl = imageAsDataUrl; this._imageData = imageData; } /** * Extracts the Base64 data out of the given dataUrl. * @param dataUrl the given dataUrl * @param mimeType the mimeType of the data */ static getDataFromDataUrl(dataUrl, mimeType) { return dataUrl.replace(`data:${mimeType};base64,`, ''); } /** * Get the base64 encoded image data * @returns base64 data of the image */ get imageAsBase64() { return this._imageAsBase64 ? this._imageAsBase64 : this._imageAsBase64 = WebcamImage.getDataFromDataUrl(this._imageAsDataUrl, this._mimeType); } /** * Get the encoded image as dataUrl * @returns the dataUrl of the image */ get imageAsDataUrl() { return this._imageAsDataUrl; } /** * Get the ImageData object associated with the canvas' 2d context. * @returns the ImageData of the canvas's 2d context. */ get imageData() { return this._imageData; } } class WebcamUtil { /** * Lists available videoInput devices * @returns a list of media device info. */ static getAvailableVideoInputs() { if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { return Promise.reject('enumerateDevices() not supported.'); } return new Promise((resolve, reject) => { navigator.mediaDevices.enumerateDevices() .then((devices) => { resolve(devices.filter((device) => device.kind === 'videoinput')); }) .catch(err => { reject(err.message || err); }); }); } } class WebcamComponent { constructor() { /** Defines the max width of the webcam area in px */ this.width = 640; /** Defines the max height of the webcam area in px */ this.height = 480; /** Defines base constraints to apply when requesting video track from UserMedia */ this.videoOptions = WebcamComponent.DEFAULT_VIDEO_OPTIONS; /** Flag to enable/disable camera switch. If enabled, a switch icon will be displayed if multiple cameras were found */ this.allowCameraSwitch = true; /** Flag to control whether an ImageData object is stored into the WebcamImage object. */ this.captureImageData = false; /** The image type to use when capturing snapshots */ this.imageType = WebcamComponent.DEFAULT_IMAGE_TYPE; /** The image quality to use when capturing snapshots (number between 0 and 1) */ this.imageQuality = WebcamComponent.DEFAULT_IMAGE_QUALITY; /** EventEmitter which fires when an image has been captured */ this.imageCapture = new EventEmitter(); /** Emits a mediaError if webcam cannot be initialized (e.g. missing user permissions) */ this.initError = new EventEmitter(); /** Emits when the webcam video was clicked */ this.imageClick = new EventEmitter(); /** Emits the active deviceId after the active video device was switched */ this.cameraSwitched = new EventEmitter(); /** available video devices */ this.availableVideoInputs = []; /** Indicates whether the video device is ready to be switched */ this.videoInitialized = false; /** Index of active video in availableVideoInputs */ this.activeVideoInputIndex = -1; /** MediaStream object in use for streaming UserMedia data */ this.mediaStream = null; /** width and height of the active video stream */ this.activeVideoSettings = null; } /** * If the given Observable emits, an image will be captured and emitted through 'imageCapture' EventEmitter */ set trigger(trigger) { if (this.triggerSubscription) { this.triggerSubscription.unsubscribe(); } // Subscribe to events from this Observable to take snapshots this.triggerSubscription = trigger.subscribe(() => { this.takeSnapshot(); }); } /** * If the given Observable emits, the active webcam will be switched to the one indicated by the emitted value. * @param switchCamera Indicates which webcam to switch to * true: cycle forwards through available webcams * false: cycle backwards through available webcams * string: activate the webcam with the given id */ set switchCamera(switchCamera) { if (this.switchCameraSubscription) { this.switchCameraSubscription.unsubscribe(); } // Subscribe to events from this Observable to switch video device this.switchCameraSubscription = switchCamera.subscribe((value) => { if (typeof value === 'string') { // deviceId was specified this.switchToVideoInput(value); } else { // direction was specified this.rotateVideoInput(value !== false); } }); } /** * Get MediaTrackConstraints to request streaming the given device * @param deviceId * @param baseMediaTrackConstraints base constraints to merge deviceId-constraint into * @returns */ static getMediaConstraintsForDevice(deviceId, baseMediaTrackConstraints) { const result = baseMediaTrackConstraints ? baseMediaTrackConstraints : this.DEFAULT_VIDEO_OPTIONS; if (deviceId) { result.deviceId = { exact: deviceId }; } return result; } /** * Tries to harvest the deviceId from the given mediaStreamTrack object. * Browsers populate this object differently; this method tries some different approaches * to read the id. * @param mediaStreamTrack * @returns deviceId if found in the mediaStreamTrack */ static getDeviceIdFromMediaStreamTrack(mediaStreamTrack) { if (mediaStreamTrack.getSettings && mediaStreamTrack.getSettings() && mediaStreamTrack.getSettings().deviceId) { return mediaStreamTrack.getSettings().deviceId; } else if (mediaStreamTrack.getConstraints && mediaStreamTrack.getConstraints() && mediaStreamTrack.getConstraints().deviceId) { const deviceIdObj = mediaStreamTrack.getConstraints().deviceId; return WebcamComponent.getValueFromConstrainDOMString(deviceIdObj); } } /** * Tries to harvest the facingMode from the given mediaStreamTrack object. * Browsers populate this object differently; this method tries some different approaches * to read the value. * @param mediaStreamTrack * @returns facingMode if found in the mediaStreamTrack */ static getFacingModeFromMediaStreamTrack(mediaStreamTrack) { if (mediaStreamTrack) { if (mediaStreamTrack.getSettings && mediaStreamTrack.getSettings() && mediaStreamTrack.getSettings().facingMode) { return mediaStreamTrack.getSettings().facingMode; } else if (mediaStreamTrack.getConstraints && mediaStreamTrack.getConstraints() && mediaStreamTrack.getConstraints().facingMode) { const facingModeConstraint = mediaStreamTrack.getConstraints().facingMode; return WebcamComponent.getValueFromConstrainDOMString(facingModeConstraint); } } } /** * Determines whether the given mediaStreamTrack claims itself as user facing * @param mediaStreamTrack */ static isUserFacing(mediaStreamTrack) { const facingMode = WebcamComponent.getFacingModeFromMediaStreamTrack(mediaStreamTrack); return facingMode ? 'user' === facingMode.toLowerCase() : false; } /** * Extracts the value from the given ConstrainDOMString * @param constrainDOMString */ static getValueFromConstrainDOMString(constrainDOMString) { if (constrainDOMString) { if (constrainDOMString instanceof String) { return String(constrainDOMString); } else if (Array.isArray(constrainDOMString) && Array(constrainDOMString).length > 0) { return String(constrainDOMString[0]); } else if (typeof constrainDOMString === 'object') { if (constrainDOMString['exact']) { return String(constrainDOMString['exact']); } else if (constrainDOMString['ideal']) { return String(constrainDOMString['ideal']); } } } return null; } ngAfterViewInit() { this.detectAvailableDevices() .then(() => { // start video this.switchToVideoInput(null); }) .catch((err) => { this.initError.next({ message: err }); // fallback: still try to load webcam, even if device enumeration failed this.switchToVideoInput(null); }); } ngOnDestroy() { this.stopMediaTracks(); this.unsubscribeFromSubscriptions(); } /** * Takes a snapshot of the current webcam's view and emits the image as an event */ takeSnapshot() { // set canvas size to actual video size const _video = this.nativeVideoElement; const dimensions = { width: this.width, height: this.height }; if (_video.videoWidth) { dimensions.width = _video.videoWidth; dimensions.height = _video.videoHeight; } const _canvas = this.canvas.nativeElement; _canvas.width = dimensions.width; _canvas.height = dimensions.height; // paint snapshot image to canvas const context2d = _canvas.getContext('2d'); context2d.drawImage(_video, 0, 0); // read canvas content as image const mimeType = this.imageType ? this.imageType : WebcamComponent.DEFAULT_IMAGE_TYPE; const quality = this.imageQuality ? this.imageQuality : WebcamComponent.DEFAULT_IMAGE_QUALITY; const dataUrl = _canvas.toDataURL(mimeType, quality); // get the ImageData object from the canvas' context. let imageData = null; if (this.captureImageData) { imageData = context2d.getImageData(0, 0, _canvas.width, _canvas.height); } this.imageCapture.next(new WebcamImage(dataUrl, mimeType, imageData)); } /** * Switches to the next/previous video device * @param forward */ rotateVideoInput(forward) { if (this.availableVideoInputs && this.availableVideoInputs.length > 1) { const increment = forward ? 1 : (this.availableVideoInputs.length - 1); const nextInputIndex = (this.activeVideoInputIndex + increment) % this.availableVideoInputs.length; this.switchToVideoInput(this.availableVideoInputs[nextInputIndex].deviceId); } } /** * Switches the camera-view to the specified video device */ switchToVideoInput(deviceId) { this.videoInitialized = false; this.stopMediaTracks(); this.initWebcam(deviceId, this.videoOptions); } /** * Event-handler for video resize event. * Triggers Angular change detection so that new video dimensions get applied */ videoResize() { // here to trigger Angular change detection } get videoWidth() { const videoRatio = this.getVideoAspectRatio(); return Math.min(this.width, this.height * videoRatio); } get videoHeight() { const videoRatio = this.getVideoAspectRatio(); return Math.min(this.height, this.width / videoRatio); } get videoStyleClasses() { let classes = ''; if (this.isMirrorImage()) { classes += 'mirrored '; } return classes.trim(); } get nativeVideoElement() { return this.video.nativeElement; } /** * Returns the video aspect ratio of the active video stream */ getVideoAspectRatio() { // calculate ratio from video element dimensions if present const videoElement = this.nativeVideoElement; if (videoElement.videoWidth && videoElement.videoWidth > 0 && videoElement.videoHeight && videoElement.videoHeight > 0) { return videoElement.videoWidth / videoElement.videoHeight; } // nothing present - calculate ratio based on width/height params return this.width / this.height; } /** * Init webcam live view */ initWebcam(deviceId, userVideoTrackConstraints) { const _video = this.nativeVideoElement; if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { // merge deviceId -> userVideoTrackConstraints const videoTrackConstraints = WebcamComponent.getMediaConstraintsForDevice(deviceId, userVideoTrackConstraints); navigator.mediaDevices.getUserMedia({ video: videoTrackConstraints }) .then((stream) => { this.mediaStream = stream; _video.srcObject = stream; _video.play(); this.activeVideoSettings = stream.getVideoTracks()[0].getSettings(); const activeDeviceId = WebcamComponent.getDeviceIdFromMediaStreamTrack(stream.getVideoTracks()[0]); this.cameraSwitched.next(activeDeviceId); // Initial detect may run before user gave permissions, returning no deviceIds. This prevents later camera switches. (#47) // Run detect once again within getUserMedia callback, to make sure this time we have permissions and get deviceIds. this.detectAvailableDevices() .then(() => { this.activeVideoInputIndex = activeDeviceId ? this.availableVideoInputs .findIndex((mediaDeviceInfo) => mediaDeviceInfo.deviceId === activeDeviceId) : -1; this.videoInitialized = true; }) .catch(() => { this.activeVideoInputIndex = -1; this.videoInitialized = true; }); }) .catch((err) => { this.initError.next({ message: err.message, mediaStreamError: err }); }); } else { this.initError.next({ message: 'Cannot read UserMedia from MediaDevices.' }); } } getActiveVideoTrack() { return this.mediaStream ? this.mediaStream.getVideoTracks()[0] : null; } isMirrorImage() { if (!this.getActiveVideoTrack()) { return false; } // check for explicit mirror override parameter { let mirror = 'auto'; if (this.mirrorImage) { if (typeof this.mirrorImage === 'string') { mirror = String(this.mirrorImage).toLowerCase(); } else { // WebcamMirrorProperties if (this.mirrorImage.x) { mirror = this.mirrorImage.x.toLowerCase(); } } } switch (mirror) { case 'always': return true; case 'never': return false; } } // default: enable mirroring if webcam is user facing return WebcamComponent.isUserFacing(this.getActiveVideoTrack()); } /** * Stops all active media tracks. * This prevents the webcam from being indicated as active, * even if it is no longer used by this component. */ stopMediaTracks() { if (this.mediaStream && this.mediaStream.getTracks) { // pause video to prevent mobile browser freezes this.nativeVideoElement.pause(); // getTracks() returns all media tracks (video+audio) this.mediaStream.getTracks() .forEach((track) => track.stop()); } } /** * Unsubscribe from all open subscriptions */ unsubscribeFromSubscriptions() { if (this.triggerSubscription) { this.triggerSubscription.unsubscribe(); } if (this.switchCameraSubscription) { this.switchCameraSubscription.unsubscribe(); } } /** * Reads available input devices */ detectAvailableDevices() { return new Promise((resolve, reject) => { WebcamUtil.getAvailableVideoInputs() .then((devices) => { this.availableVideoInputs = devices; resolve(devices); }) .catch(err => { this.availableVideoInputs = []; reject(err); }); }); } } WebcamComponent.DEFAULT_VIDEO_OPTIONS = { facingMode: 'environment' }; WebcamComponent.DEFAULT_IMAGE_TYPE = 'image/jpeg'; WebcamComponent.DEFAULT_IMAGE_QUALITY = 0.92; WebcamComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: WebcamComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); WebcamComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.0", type: WebcamComponent, selector: "webcam", inputs: { width: "width", height: "height", videoOptions: "videoOptions", allowCameraSwitch: "allowCameraSwitch", mirrorImage: "mirrorImage", captureImageData: "captureImageData", imageType: "imageType", imageQuality: "imageQuality", trigger: "trigger", switchCamera: "switchCamera" }, outputs: { imageCapture: "imageCapture", initError: "initError", imageClick: "imageClick", cameraSwitched: "cameraSwitched" }, viewQueries: [{ propertyName: "video", first: true, predicate: ["video"], descendants: true, static: true }, { propertyName: "canvas", first: true, predicate: ["canvas"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"webcam-wrapper\" (click)=\"imageClick.next();\">\r\n <video #video [width]=\"videoWidth\" [height]=\"videoHeight\" [class]=\"videoStyleClasses\" autoplay muted playsinline (resize)=\"videoResize()\"></video>\r\n <div class=\"camera-switch\" *ngIf=\"allowCameraSwitch && availableVideoInputs.length > 1 && videoInitialized\" (click)=\"rotateVideoInput(true)\"></div>\r\n <canvas #canvas [width]=\"width\" [height]=\"height\"></canvas>\r\n</div>\r\n", styles: [".webcam-wrapper{display:inline-block;position:relative;line-height:0}.webcam-wrapper video.mirrored{transform:scaleX(-1)}.webcam-wrapper canvas{display:none}.webcam-wrapper .camera-switch{background-color:#0000001a;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAE9UlEQVR42u2aT2hdRRTGf+cRQqghSqihdBFDkRISK2KDfzDWxHaRQHEhaINKqa1gKQhd6EZLN+IidCH+Q0oWIkVRC21BQxXRitVaSbKoJSGtYGoK2tQ/tU1jY5v0c5F54Xl7b/KSO/PyEt+3e5f75p7zzZwzZ74zUEIJJfyfYaEGllQGVAGZlENdBy6Z2cSiYFTSKkkfS/pH/nBF0kFJdUW9AiRVASeAukD8DgNrzOySrwEzng18KaDzALXuG8W3AiStAvqBisBRNg40mtlPxbYCOgvgPO4bncWW+JpVeDQXRQhIygDfA00F5r0XuNfMrgclQFI98DDQCNQA5ZFXqoCWBVp8XwHRHeEqcN7loy/NbHBesyqpQ1KfFj/6nC+ZvFaApFrgPaCZpYVvgCfNbDiRAElNwGFg+RIt/X8H2s2s9wYCJDUAR4HqJX7++RN40MwGpgmQVAH0AQ2BPz4AHHPl8nBOAqtyFWQjsA6oL4Ada81sPDv7uwImod8kvSJp9RyS8O2SXnb/DYVd2Y9VSroQ4ANXJO2WVJmixqh0kzMWwL4LkiqRtDnA4D1zmfE8j9g9AezcnAHaPcfXdbfdnPZ2Yps6+DwAvO/Z1naTdApY7Xng48BDZnY1MpMVQBuw3iXc5Tnb0wBwBPjUzP6eoezuArZ6svM0geJLkvZEYnl3nkntoqROSbckSW2Suj3ZOIangc7GPJuUtNGdFIfmMeavktoSSKiW9LMPw30Q8JqkekmjCbOZRhuclLQjgYSNxUBAj6RyZ9ATgUJpUtJTCSR8vpAEXHAyWK5BXYFIGHOlepSAloUk4NEYgyoknQhEwhFJ0e8h6VSaQeerCb5uZgdi9utxYBNwOUD93hIVXswM4INCi6K9wAszFC2DwLOBDjHbYp59karIUnRdzYy/3ClqVklaUhfwTICj7K25OqA7a4wWagVsm4Me/xzwg2cCqqONFzO7DPxSCAJi436GUBgHHguQD2oTlJ55oSzP9ybccsttSJw1szdjFOSnI/8dTCGZHwcORp4Nx7y3B1iZ8/sm4MW8/Euxg5wIsS/HaAp3zeP4/G7obRDXI4jiTIA22H7Xdc7X+S3A5lC7QBQ357aq3VAjCeSkwUfAJrfvz+R8A9ADLAtZB+TinpjC5JMA+//jwPZZnF8G7J+L8z4IWB/zbG+gIujVWfLBW/NStVMmqaG4POJRsIjix7h8IGnLQuoBbQki5sVAJHyYm7YkNaRRtXwQ8G1cHpX0iKRrgUjYno17Sf0LrQhJUkdCeHWkVITGJI0k1QeS3ikGSUzOyJUJJNznYneuOCnpTldcxa2kP3xJYqOeSDjqZG8ShJLnE8TTuMS6Iyu1BW7djZqkfo9N0QOuYJmYQddfB7RG+gLTNzqAY9FrL+5/nwEbvDdJJe3zzOrhNP3AWRqmk55t3ZcBuj3b2gb0Sbrbo/NNzk7fFzu7s/E5EiC+rrmeQU0Kx2skvRFoOx2ZzlmSdgbsw49JetvtBpk8nM64d/cGbNtJ0s7cGyJlwHeEv+t3nqnLSgPAUOSGyG3AHUxdzqoJbEcvcL+ZTeTeEapzJKxgaeOcc/7Mf06D7kFrguS0VDAMtGadv+E47DT9tcChJej8ISfpD+abgTe45uOkFi8mnQ+JBVQ+d4VXuOptjavcyot8pq86mfwk8LWZnaOEEkoooYQSSojDv8AhQNeGfe0jAAAAAElFTkSuQmCC);background-repeat:no-repeat;border-radius:5px;position:absolute;right:13px;top:10px;height:48px;width:48px;background-size:80%;cursor:pointer;background-position:center;transition:background-color .2s ease}.webcam-wrapper .camera-switch:hover{background-color:#0000002e}\n"], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: WebcamComponent, decorators: [{ type: Component, args: [{ selector: 'webcam', template: "<div class=\"webcam-wrapper\" (click)=\"imageClick.next();\">\r\n <video #video [width]=\"videoWidth\" [height]=\"videoHeight\" [class]=\"videoStyleClasses\" autoplay muted playsinline (resize)=\"videoResize()\"></video>\r\n <div class=\"camera-switch\" *ngIf=\"allowCameraSwitch && availableVideoInputs.length > 1 && videoInitialized\" (click)=\"rotateVideoInput(true)\"></div>\r\n <canvas #canvas [width]=\"width\" [height]=\"height\"></canvas>\r\n</div>\r\n", styles: [".webcam-wrapper{display:inline-block;position:relative;line-height:0}.webcam-wrapper video.mirrored{transform:scaleX(-1)}.webcam-wrapper canvas{display:none}.webcam-wrapper .camera-switch{background-color:#0000001a;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAE9UlEQVR42u2aT2hdRRTGf+cRQqghSqihdBFDkRISK2KDfzDWxHaRQHEhaINKqa1gKQhd6EZLN+IidCH+Q0oWIkVRC21BQxXRitVaSbKoJSGtYGoK2tQ/tU1jY5v0c5F54Xl7b/KSO/PyEt+3e5f75p7zzZwzZ74zUEIJJfyfYaEGllQGVAGZlENdBy6Z2cSiYFTSKkkfS/pH/nBF0kFJdUW9AiRVASeAukD8DgNrzOySrwEzng18KaDzALXuG8W3AiStAvqBisBRNg40mtlPxbYCOgvgPO4bncWW+JpVeDQXRQhIygDfA00F5r0XuNfMrgclQFI98DDQCNQA5ZFXqoCWBVp8XwHRHeEqcN7loy/NbHBesyqpQ1KfFj/6nC+ZvFaApFrgPaCZpYVvgCfNbDiRAElNwGFg+RIt/X8H2s2s9wYCJDUAR4HqJX7++RN40MwGpgmQVAH0AQ2BPz4AHHPl8nBOAqtyFWQjsA6oL4Ada81sPDv7uwImod8kvSJp9RyS8O2SXnb/DYVd2Y9VSroQ4ANXJO2WVJmixqh0kzMWwL4LkiqRtDnA4D1zmfE8j9g9AezcnAHaPcfXdbfdnPZ2Yps6+DwAvO/Z1naTdApY7Xng48BDZnY1MpMVQBuw3iXc5Tnb0wBwBPjUzP6eoezuArZ6svM0geJLkvZEYnl3nkntoqROSbckSW2Suj3ZOIangc7GPJuUtNGdFIfmMeavktoSSKiW9LMPw30Q8JqkekmjCbOZRhuclLQjgYSNxUBAj6RyZ9ATgUJpUtJTCSR8vpAEXHAyWK5BXYFIGHOlepSAloUk4NEYgyoknQhEwhFJ0e8h6VSaQeerCb5uZgdi9utxYBNwOUD93hIVXswM4INCi6K9wAszFC2DwLOBDjHbYp59karIUnRdzYy/3ClqVklaUhfwTICj7K25OqA7a4wWagVsm4Me/xzwg2cCqqONFzO7DPxSCAJi436GUBgHHguQD2oTlJ55oSzP9ybccsttSJw1szdjFOSnI/8dTCGZHwcORp4Nx7y3B1iZ8/sm4MW8/Euxg5wIsS/HaAp3zeP4/G7obRDXI4jiTIA22H7Xdc7X+S3A5lC7QBQ357aq3VAjCeSkwUfAJrfvz+R8A9ADLAtZB+TinpjC5JMA+//jwPZZnF8G7J+L8z4IWB/zbG+gIujVWfLBW/NStVMmqaG4POJRsIjix7h8IGnLQuoBbQki5sVAJHyYm7YkNaRRtXwQ8G1cHpX0iKRrgUjYno17Sf0LrQhJUkdCeHWkVITGJI0k1QeS3ikGSUzOyJUJJNznYneuOCnpTldcxa2kP3xJYqOeSDjqZG8ShJLnE8TTuMS6Iyu1BW7djZqkfo9N0QOuYJmYQddfB7RG+gLTNzqAY9FrL+5/nwEbvDdJJe3zzOrhNP3AWRqmk55t3ZcBuj3b2gb0Sbrbo/NNzk7fFzu7s/E5EiC+rrmeQU0Kx2skvRFoOx2ZzlmSdgbsw49JetvtBpk8nM64d/cGbNtJ0s7cGyJlwHeEv+t3nqnLSgPAUOSGyG3AHUxdzqoJbEcvcL+ZTeTeEapzJKxgaeOcc/7Mf06D7kFrguS0VDAMtGadv+E47DT9tcChJej8ISfpD+abgTe45uOkFi8mnQ+JBVQ+d4VXuOptjavcyot8pq86mfwk8LWZnaOEEkoooYQSSojDv8AhQNeGfe0jAAAAAElFTkSuQmCC);background-repeat:no-repeat;border-radius:5px;position:absolute;right:13px;top:10px;height:48px;width:48px;background-size:80%;cursor:pointer;background-position:center;transition:background-color .2s ease}.webcam-wrapper .camera-switch:hover{background-color:#0000002e}\n"] }] }], propDecorators: { width: [{ type: Input }], height: [{ type: Input }], videoOptions: [{ type: Input }], allowCameraSwitch: [{ type: Input }], mirrorImage: [{ type: Input }], captureImageData: [{ type: Input }], imageType: [{ type: Input }], imageQuality: [{ type: Input }], imageCapture: [{ type: Output }], initError: [{ type: Output }], imageClick: [{ type: Output }], cameraSwitched: [{ type: Output }], video: [{ type: ViewChild, args: ['video', { static: true }] }], canvas: [{ type: ViewChild, args: ['canvas', { static: true }] }], trigger: [{ type: Input }], switchCamera: [{ type: Input }] } }); const COMPONENTS = [ WebcamComponent ]; class WebcamModule { } WebcamModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: WebcamModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); WebcamModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: WebcamModule, declarations: [WebcamComponent], imports: [CommonModule], exports: [WebcamComponent] }); WebcamModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: WebcamModule, imports: [[ CommonModule ]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: WebcamModule, decorators: [{ type: NgModule, args: [{ imports: [ CommonModule ], declarations: [ COMPONENTS ], exports: [ COMPONENTS ] }] }] }); class WebcamInitError { constructor() { this.message = null; this.mediaStreamError = null; } } class WebcamMirrorProperties { } /** * Generated bundle index. Do not edit. */ export { WebcamComponent, WebcamImage, WebcamInitError, WebcamMirrorProperties, WebcamModule, WebcamUtil };