UNPKG

ngx-cam-shoot

Version:

An angular component to use you device's cameras easily. Obtain and save images faster. Thought to use on mobile devices.

939 lines 66.7 kB
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, HostListener, Input, ViewChild, Output, Component } from '@angular/core';
import * as i2 from '@angular/forms';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';

//import { Subscription } from 'rxjs';
var eCamShootType;
(function (eCamShootType) {
    eCamShootType["DEFAULT"] = "DEFAULT";
    eCamShootType["SELFIE"] = "SELFIE";
    eCamShootType["DOCFRONT"] = "DOCFRONT";
    eCamShootType["DOCBACK"] = "DOCBACK";
})(eCamShootType || (eCamShootType = {}));
var eCamShootFaceMode;
(function (eCamShootFaceMode) {
    eCamShootFaceMode["USER"] = "user";
    eCamShootFaceMode["ENVIRONMENT"] = "environment";
})(eCamShootFaceMode || (eCamShootFaceMode = {}));
class NgxCamShoot {
    sendImage = new EventEmitter();
    stream;
    modalCapture = false;
    isCaptured = false;
    imageCaptured;
    error = '';
    debug = '';
    video;
    canvas;
    config;
    canChangeMode = true;
    type = eCamShootType.DEFAULT;
    color = '#282828';
    displayTitle = !0;
    title = 'Capture image';
    showFaceMode = false;
    usePreview = true;
    showErrors = false;
    debugMode = false;
    btnTakeAnother = 'Take another';
    btnAcceptCapture = 'Accept capture';
    havePermissions = false;
    isChangingDevice = false;
    faceMode = eCamShootFaceMode.USER;
    canUseFlash = false;
    canActiveFlash = false;
    isFlashActive = false;
    //private zoomSubs!: Subscription;
    zoom = new FormControl(null);
    zoomConfig = { min: -1, max: 10, step: 2 };
    canUseZoom = false;
    canActiveZoom = false;
    devices = [];
    //private deviceSubs!: Subscription;
    device = new FormControl(null);
    displayPreview = false;
    isMobile = false;
    hasTouchSupport = false;
    isLandscape = false;
    orientationDegs = 0;
    screen_w = 0;
    screen_h = 0;
    fullScreenStart = false;
    maxTryStream = 25;
    resize() {
        this.debug += "[resize] start.\n";
        this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
        this.hasTouchSupport = this.hasTouch(navigator); //'ontouchstart' in window || navigator.maxTouchPoints > 0;
        this.isLandscape = window.matchMedia("(orientation: landscape)").matches && this.hasTouchSupport;
        //this.isLandscape = screen.availHeight < screen.availWidth;
        if (this.isLandscape && window.orientation != undefined) {
            this.orientationDegs = window.orientation;
            this.debug += "[resize] have orientation: ", window.orientation, "\n";
        }
        else {
            this.orientationDegs = 0;
        }
        this.screen_w = screen.availWidth;
        this.screen_h = screen.availHeight;
        this.debug += "[resize] screen " + this.screen_w + "x" + this.screen_h + ".\n";
    }
    constructor() {
        this.initConfig(this.config);
    }
    ngOnChanges(changes) {
        if (changes['canChangeMode']) {
            console.log('canChangeMode', changes['canChangeMode'].currentValue);
            this.canChangeMode = changes['canChangeMode'].currentValue;
        }
        if (changes['type']) {
            if (this.type == eCamShootType.SELFIE && !this.canChangeMode) {
                this.faceMode = eCamShootFaceMode.USER;
            }
            else {
                this.faceMode = eCamShootFaceMode.ENVIRONMENT;
            }
            if (!changes['type'].firstChange) {
                this.device.reset();
                this.clear();
                this.initDevices();
            }
        }
    }
    ngOnInit() {
        this.resize();
        /* this.deviceSubs = */ this.device.valueChanges.subscribe((v) => {
            if (v == null)
                return;
            console.log('device changed', v);
            this.debug += "[ngOnInit] device value changes.\n";
            this.isChangingDevice = true;
            this.clearAndLoadDevices();
            this.checkDeviceMode(v);
        });
        /* this.zoomSubs = */ this.zoom.valueChanges.subscribe((v) => {
            if (v != null) {
                this.updateZoom(v);
            }
        });
    }
    initConfig(config) {
        if (config == undefined)
            return;
        this.displayTitle = config.displayTitle ?? this.displayTitle;
        this.title = config.title ?? this.title;
        this.showFaceMode = config.showFaceMode ?? this.showFaceMode;
        this.canChangeMode = config.canChangeMode ?? this.canChangeMode;
        this.type = config.type ?? this.type;
        this.color = config.color ?? this.color;
        this.usePreview = config.usePreview ?? this.usePreview;
        this.btnTakeAnother = config.btnTakeAnother ?? this.btnTakeAnother;
        this.btnAcceptCapture = config.btnAcceptCapture ?? this.btnAcceptCapture;
    }
    initCapture(faceMode = eCamShootFaceMode.USER) {
        this.debug += "[initCapture] start;\n";
        this.isChangingDevice = true;
        this.modalCapture = true;
        this.faceMode = faceMode;
        this.debug += "[initCapture] modalCapture = true;\n";
        document.getElementsByTagName('body')[0].style.overflowY = 'hidden';
        document.getElementsByTagName('body')[0].focus();
        this.requestPermissions();
    }
    takeCapture() {
        this.modalCapture = false;
        document.getElementsByTagName('body')[0].style.overflowY = 'auto';
        this.drawImageToCanvas(this.video.nativeElement);
    }
    takeAnother() {
        this.debug += "[takeAnother] start;\n";
        this.clear();
        this.initCapture(this.faceMode);
    }
    sendCapture() {
        this.cancelFullScreen();
        this.send();
        this.clear();
    }
    close() {
        this.cancelFullScreen();
        this.modalCapture = false;
        this.devices = [];
        this.device.reset(null, { emitEvent: false });
        /* this.deviceSubs.unsubscribe();
        this.zoomSubs.unsubscribe(); */
        this.clear();
    }
    clearAndLoadDevices() {
        this.clear();
        setTimeout(() => {
            this.loadDevices();
        }, 250);
    }
    clear() {
        this.debug += "[clear] start.\n";
        this.imageCaptured = undefined;
        this.isCaptured = false;
        this.canUseFlash = false;
        this.canActiveFlash = false;
        this.isFlashActive = false;
        this.canUseZoom = false;
        this.canActiveZoom = false;
        this.displayPreview = false;
        try {
            const webcam = this.video.nativeElement;
            if (webcam) {
                this.debug += "[clear] exist video, setting pause, empty and null.\n";
                webcam.pause();
                webcam.src = "";
                webcam.srcObject = null;
            }
        }
        catch (e) {
            this.debug += "[clear] webcam error: " + e.message + ", setting pause, empty and null.\n";
            this.error += "[clear] webcam error: " + e.message + ", setting pause, empty and null.\n";
        }
        if (this.stream === undefined)
            return;
        try {
            let me = this;
            this.stream.getTracks().forEach(function (track) {
                me.debug += "[clear] getTracks(), id: " + track.id + ".\n";
                if (track.readyState == 'live' && track.kind === 'video') {
                    me.debug += "[clear] stopping track id: " + track.id + ".\n";
                    track.stop();
                    /* if(me.stream!=undefined){
                      me.stream.removeTrack(track);
                    } */
                }
            });
            this.debug += "[clear] set stream to undefined.\n";
            this.stream = undefined;
        }
        catch (e) {
            console.log('[STRM] ' + e.message);
        }
    }
    drawImageToCanvas(image) {
        let ctx = this.canvas.nativeElement.getContext("2d");
        //console.log('draw type',this.type)
        //const webcam = document.getElementById('videocap') as HTMLVideoElement;//functional
        const webcam = this.video.nativeElement;
        /* if(this.type!=eCamShootType.SELFIE){
    
          this.canvas.nativeElement.width = webcam.videoHeight;
          this.canvas.nativeElement.height = webcam.videoWidth;
    
          ctx.save();
    
          ctx.translate(webcam.videoHeight/2, webcam.videoWidth/2);
          ctx.rotate(-90 * Math.PI/180);
          ctx.drawImage(image, -(webcam.videoWidth/2), -(webcam.videoHeight/2));
          ctx.restore();
        }else{
          this.canvas.nativeElement.width = webcam.videoWidth;
          this.canvas.nativeElement.height = webcam.videoHeight;
          ctx.scale(-1, 1);
          ctx.drawImage(image, 0, 0, this.canvas.nativeElement.width*-1, this.canvas.nativeElement.height);
        } */
        /* if(this.type==eCamShootType.SELFIE){
          if(this.faceMode==eCamShootFaceMode.USER){
            this.canvas.nativeElement.width = webcam.videoWidth;
            this.canvas.nativeElement.height = webcam.videoHeight;
            ctx.scale(-1, 1);
            ctx.drawImage(image, 0, 0, this.canvas.nativeElement.width*-1, this.canvas.nativeElement.height);
          }else{
            this.canvas.nativeElement.width = webcam.videoWidth;
            this.canvas.nativeElement.height = webcam.videoHeight;
            ctx.drawImage(image, 0, 0, this.canvas.nativeElement.width, this.canvas.nativeElement.height);
          }
        }else{
          this.canvas.nativeElement.width = webcam.videoHeight;
          this.canvas.nativeElement.height = webcam.videoWidth;
    
          ctx.save();
    
          ctx.translate(webcam.videoHeight/2, webcam.videoWidth/2);
          ctx.rotate(-90 * Math.PI/180);
          ctx.drawImage(image, -(webcam.videoWidth/2), -(webcam.videoHeight/2));
          ctx.restore();
        } */
        //is front
        if (this.faceMode == eCamShootFaceMode.USER) {
            this.canvas.nativeElement.width = webcam.videoWidth;
            this.canvas.nativeElement.height = webcam.videoHeight;
            ctx?.scale(-1, 1);
            ctx?.drawImage(image, 0, 0, this.canvas.nativeElement.width * -1, this.canvas.nativeElement.height);
        }
        else {
            //is back
            //without focus marker
            if (this.type == eCamShootType.DEFAULT) {
                this.canvas.nativeElement.width = webcam.videoWidth;
                this.canvas.nativeElement.height = webcam.videoHeight;
                ctx?.drawImage(image, 0, 0, this.canvas.nativeElement.width, this.canvas.nativeElement.height);
            }
            else {
                //shoot document (rotate)
                this.canvas.nativeElement.width = webcam.videoHeight;
                this.canvas.nativeElement.height = webcam.videoWidth;
                ctx?.save();
                ctx?.translate(webcam.videoHeight / 2, webcam.videoWidth / 2);
                ctx?.rotate(-90 * Math.PI / 180);
                ctx?.drawImage(image, -(webcam.videoWidth / 2), -(webcam.videoHeight / 2));
                ctx?.restore();
            }
        }
        this.imageCaptured = this.canvas.nativeElement.toDataURL("image/png");
        this.isCaptured = true;
        if (!this.usePreview) {
            this.sendCapture();
        }
        else {
            this.displayPreview = true;
        }
    }
    send() {
        this.sendImage.emit(this.imageCaptured);
    }
    async initDevices() {
        this.debug += "[initDevices] start;\n";
        if (this.devices.length > 0) {
            this.debug += "[initDevices] devices previously loaded, continue to loadDevices();\n";
            this.loadDevices();
            return;
        }
        this.devices = [];
        if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia != undefined) {
            this.debug += "[initDevices] navigator.mediaDevices exist.\n";
            await navigator
                .mediaDevices
                .enumerateDevices()
                .then(devices => {
                this.debug += "[initDevices] enumerateDevices() executed.\n";
                const videoDevies = devices.filter((d) => d.kind == 'videoinput');
                this.debug += "[initDevices] enumerateDevices() found " + videoDevies.length + " video devices.\n";
                videoDevies.forEach((device, i) => {
                    this.debug += "[initDevices] enumerateDevices() forEach index: " + i + ".\n";
                    this.pushDevice(device);
                });
                if (this.devices.length == 0) {
                    this.debug += "[initDevices] don't have camera devices.\n";
                    this.error += "No posees una entrada de camara.\n";
                }
                else {
                    if (this.devices[0].deviceId == '') {
                        this.debug += "[initDevices] device default is empty, you don't have permissons, go to loadDevices().\n";
                        this.loadDevices();
                        return;
                    }
                    this.assignDevice();
                }
            });
        }
        else {
            this.debug += "[initDevices] navigator.mediaDevices don't exist.\n";
            this.error += "No tienes acceso a los dispositivos.\n";
        }
    }
    cancelFullScreen() {
        this.debug += "[cancelFullScreen] start.\n";
        var el = document;
        var cancelFullScreenMethod = el.exitFullscreen || el.webkitExitFullscreen
            || el.mozCancelFullScreen || el.msExitFullscreen;
        if (cancelFullScreenMethod && el.fullscreenElement) {
            this.debug += "[cancelFullScreen] executed.\n";
            cancelFullScreenMethod.call(el);
            this.resize();
        }
    }
    requestFullScreen() {
        this.debug += "[requestFullScreen] start.\n";
        var el = document.body;
        var requestMethod = el.requestFullScreen || el.webkitRequestFullScreen
            || el.mozRequestFullScreen || el.msRequestFullScreen;
        if (requestMethod) {
            this.debug += "[requestFullScreen] executed on body.\n";
            requestMethod.call(el);
            this.debug += "[requestFullScreen] go to resize().\n";
            this.resize();
        }
    }
    async requestPermissions() {
        //for safary (ios)
        //<meta name="viewport" content="minimal-ui, width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
        /* let body: any = document.querySelector("body");
        body.requestFullscreen().then(() => {
          //document.querySelector("body").style.overflow = "auto";
          this.debug += "[requestPermissions] se dio permiso de pantalla.\n";
        }); */
        this.debug += "[requestPermissions] start.\n";
        if (this.havePermissions) {
            this.requestFullScreen();
            this.debug += "[requestPermissions] the session already have permissions, go to initDevices().\n";
            this.initDevices();
            return;
        }
        try {
            let constraints = {
                width: { min: 640, ideal: 1280, max: 1920 },
                height: { min: 480, ideal: 720 },
                focusMode: 'continuous'
            };
            await navigator
                .mediaDevices
                .getUserMedia({
                video: constraints
            })
                .then((stream) => {
                this.havePermissions = true;
                this.requestFullScreen();
                this.debug += "[requestPermissions] permissions granted, go to initDevices().\n";
                this.initDevices();
            })
                .catch((err) => {
                this.havePermissions = false;
                this.debug += "[requestPermissions] permissions fail: " + err + ".\n";
                console.error(`you got an error: ${err}`);
            });
        }
        catch (e) {
            this.debug += "[requestPermissions] catch: " + JSON.stringify(e) + ".\n";
            console.log('[ERR] ' + e);
        }
    }
    assignDevice() {
        this.debug += "[assignDevice] start.\n";
        this.debug += "[assignDevice] devices existing: " + this.devices.length + ".\n";
        this.debug += "[assignDevice] faceMode: " + this.faceMode + ".\n";
        if (this.devices.length == 1) {
            this.debug += "[assignDevice] only have 1 device.\n";
            const firstDevice = this.devices[0];
            this.device.setValue(firstDevice.deviceId, { emitEvent: false });
            if (this.faceMode == eCamShootFaceMode.ENVIRONMENT) {
                this.debug += "[assignDevice] faceMode=ENVIRONMENT on 1 device, probably has laptop or pc, go to changeMode().\n";
                this.toogleMode();
                return;
            }
        }
        else if (this.faceMode == eCamShootFaceMode.ENVIRONMENT) {
            this.debug += "[assignDevice] faceMode=ENVIRONMENT.\n";
            if (this.getBackDevices().length > 0) {
                this.debug += "[assignDevice] set ENVIRONMENT mode device.\n";
                this.device.setValue(this.getBackDevices()[0].deviceId, { emitEvent: false });
            }
            else {
                this.debug += "[assignDevice] ENVIRONMENT devices=0. Executing changeMode().\n";
                this.toogleMode();
                return;
            }
        }
        else {
            this.debug += "[assignDevice] set USER mode device.\n";
            this.device.setValue(this.getFrontDevices()[0].deviceId, { emitEvent: false });
        }
        this.debug += "[assignDevice] execute loadDevices().\n";
        this.loadDevices();
    }
    async loadDevices(count = 1) {
        this.debug += "[loadDevices]" + (count > 1 ? '[number ' + count + "]" : '') + " start.\n";
        const iWidth = this.screen_h; //this.isLandscape?this.screen_w:this.screen_h;
        const iHeight = this.screen_w; //this.isLandscape?this.screen_h:this.screen_w;
        let videoConstraints = {
            /* width: {min: 640, ideal: 1280, max: 1920},
            height: {min: 480, ideal: 720, max: 1080}, */
            /* width: this.screen_h,
            height: this.screen_w, */
            width: iWidth,
            height: iHeight,
            focusMode: 'continuous'
        };
        if (this.device.value != null && this.device.value != '') {
            this.debug += "[loadDevices] devices has been set, init constraints with deviceId: " + this.device.value + ".\n";
            videoConstraints = {
                ...videoConstraints,
                deviceId: { exact: this.device.value }
            };
        }
        else {
            this.debug += "[loadDevices] devices has not been set, init constraints with faceMode.\n";
            videoConstraints = {
                ...videoConstraints,
                facingMode: this.faceMode
            };
        }
        if (this.stream == undefined) {
            this.debug += "[loadDevices] stream is undefined.\n";
        }
        this.startStream({ video: videoConstraints });
    }
    async startStream(constraints, count = 1) {
        this.debug += "[startStream] start.\n";
        this.debug += "[startStream] constraints: " + JSON.stringify(constraints) + ".\n";
        navigator.mediaDevices.getUserMedia(constraints)
            .then((stream) => {
            this.isChangingDevice = false;
            this.stream = stream;
            this.debug += "[startStream] stream has been initialized.\n";
            this.checkFlash(this.device.value);
            this.checkZoom();
            this.debug += "[startStream] initialize handleStream.\n";
            this.handleStream(stream);
        }, (reason) => {
            this.debug += "[startStream] getUserMedia fail: " + reason + ".\n";
            if (count > this.maxTryStream) {
                this.isChangingDevice = false;
                this.debug += "[startStream] getUserMedia fail. More than 20 times has been tried to start stream and fail.\n";
                return;
            }
            this.debug += "[startStream] getUserMedia fail. Try " + count + " time in .25s.\n";
            setTimeout(() => {
                this.startStream(constraints, count + 1);
            }, 250);
        });
    }
    handleStream(stream) {
        this.debug += "[handleStream] start.\n";
        if (stream == undefined) {
            this.debug += "[handleStream] stream is undefined, cancel action.\n";
            return;
        }
        const webcam = this.video.nativeElement;
        webcam.srcObject = stream;
        if (this.device.value == null || this.device.value == '') {
            this.debug += "[handleStream] device is null or empty.\n";
            setTimeout(() => {
                this.debug += "[handleStream] executing setTimeout to initDevices().\n";
                this.initDevices();
            }, 500);
        }
        webcam.onloadedmetadata = async (event) => {
            try {
                this.debug += "[handleStream] video sizes " + webcam.videoWidth + "x" + webcam.videoHeight + ".\n";
                await webcam.play();
            }
            catch (e) {
                console.error(e);
            }
        };
    }
    toogleMode() {
        this.debug += "[changeMode] start.\n";
        const fm = this.faceMode;
        this.debug += "[changeMode] current faceMode: " + fm + ".\n";
        this.faceMode = this.faceMode == eCamShootFaceMode.USER ? eCamShootFaceMode.ENVIRONMENT : eCamShootFaceMode.USER;
        this.debug += "[changeMode] new faceMode: " + this.faceMode + ".\n";
        let canContinue = false;
        if (this.faceMode == eCamShootFaceMode.ENVIRONMENT && this.getBackDevices().length > 0) {
            canContinue = true;
        }
        else if (this.faceMode == eCamShootFaceMode.USER && this.getFrontDevices().length > 0) {
            canContinue = true;
        }
        if (!canContinue) {
            this.debug += "[changeMode] don't have devices to change, cancel action.\n";
            return;
        }
        this.isChangingDevice = true;
        if (this.faceMode == eCamShootFaceMode.ENVIRONMENT) {
            this.debug += "[changeMode] faceMode = ENVIRONMENT.\n";
            this.debug += "[changeMode] ENVIRONMENT devices: " + this.getBackDevices().length + ".\n";
            this.device.setValue(this.getBackDevices()[0].deviceId, { emitEvent: false });
        }
        else {
            this.debug += "[changeMode] faceMode = USER.\n";
            this.debug += "[changeMode] USER devices: " + this.getFrontDevices().length + ".\n";
            this.device.setValue(this.getFrontDevices()[0].deviceId, { emitEvent: false });
        }
        this.clearAndLoadDevices();
    }
    checkFlash(deviceId) {
        this.debug += "[checkFlash] start.\n";
        if (this.stream == undefined)
            return;
        let track = this.stream.getVideoTracks()[0];
        if (!track.getCapabilities) {
            this.debug += "[checkFlash] track can't use capabilities.\n";
            this.canUseFlash = false;
            this.canActiveFlash = false;
            return;
        }
        this.canUseFlash = true;
        this.canActiveFlash = 'torch' in track.getCapabilities();
        if (deviceId != null && this.canActiveFlash) {
            this.debug += "[checkFlash] device canActiveFlash = true.\n";
            this.setDeviceFlash(deviceId, this.canActiveFlash);
        }
        this.debug += "[checkFlash] canActiveFlash: " + this.canActiveFlash + ".\n";
    }
    setDeviceFlash(deviceId, torch) {
        this.debug += "[setDeviceFlash] start.\n";
        let dev = this.devices.find((e) => e.deviceId == deviceId);
        this.debug += "[setDeviceFlash] find on devices, where deviceId: " + deviceId + ".\n";
        if (dev != undefined) {
            this.debug += "[setDeviceFlash] device found, set haveTorch to: " + torch + ".\n";
            dev.haveTorch = torch;
        }
    }
    toogleFlash() {
        this.debug += "[toogleFlash] start.\n";
        if (this.stream == undefined)
            return;
        const track = this.stream.getVideoTracks()[0];
        this.isFlashActive = !this.isFlashActive;
        this.debug += "[toogleFlash] applyAdvanceConstraint torch to " + this.isFlashActive + ".\n";
        this.applyAdvanceConstraint({ torch: this.isFlashActive });
    }
    checkZoom() {
        this.debug += "[checkZoom] start.\n";
        if (this.stream == undefined)
            return;
        const prev = this.canUseZoom;
        let track = this.stream.getVideoTracks()[0];
        if (!track.getCapabilities) {
            this.debug += "[checkZoom] track can't use capabilities.\n";
            this.canUseZoom = false;
            return;
        }
        this.canUseZoom = true;
        this.canActiveZoom = 'zoom' in track.getCapabilities();
        this.debug += "[checkZoom] canActiveZoom: " + this.canActiveZoom + ".\n";
        this.zoomConfig = track.getCapabilities().zoom;
        if (this.zoomConfig != undefined) {
            this.zoom.setValue(this.zoomConfig.min);
        }
    }
    updateZoom(zoom) {
        this.debug += "[updateZoom] start.\n";
        if (this.zoomConfig == undefined) {
            this.debug += "[updateZoom] zoomConfig is undefined, cancel.\n";
        }
        this.debug += "[updateZoom] applyAdvanceConstraint zoom to " + zoom + ".\n";
        this.applyAdvanceConstraint({ zoom: zoom });
    }
    applyAdvanceConstraint(constraint) {
        this.debug += "[applyAdvanceConstraint] start.\n";
        if (this.stream == undefined) {
            this.debug += "[applyAdvanceConstraint] stream is undefined.\n";
            return;
        }
        const track = this.stream.getVideoTracks()[0];
        this.debug += "[applyAdvanceConstraint] constraint set: " + JSON.stringify(constraint) + ".\n";
        const constraints = {
            advanced: [constraint]
        };
        track.applyConstraints(constraints)
            .then(() => {
            this.debug += "[applyAdvanceConstraint] constraints has been applied.\n";
        })
            .catch(e => {
            this.debug += "[applyAdvanceConstraint] constraints not has been applied.\n";
        });
    }
    getZoomPercent() {
        const zoomVal = this.zoom.value;
        if (zoomVal == null || zoomVal == this.zoomConfig.min)
            return '1.0';
        console.log('getZoomPercent', zoomVal);
        return ((zoomVal) / this.zoomConfig.min).toFixed(1);
    }
    checkDeviceMode(deviceId) {
        this.debug += "[checkDeviceMode] start.\n";
        let device = this.devices.filter((e) => e.deviceId == deviceId)[0];
        let isFrontDev = this.isFront(device.label);
        if (isFrontDev != device.isFront) {
            this.debug += "[checkDeviceMode] faceMode front device not match, changing.\n";
            this.faceMode = isFrontDev ? eCamShootFaceMode.USER : eCamShootFaceMode.ENVIRONMENT;
        }
    }
    isFront(label) {
        return label.match(/back|trasera/i) === null;
    }
    getFrontDevices() {
        return this.devices.filter(e => e.isFront);
    }
    getBackDevices() {
        return this.devices.filter(e => !e.isFront);
    }
    get hasMultipleDevicesOnMode() {
        if (this.faceMode == eCamShootFaceMode.USER) {
            return this.getFrontDevices().length > 1;
        }
        if (this.faceMode == eCamShootFaceMode.ENVIRONMENT) {
            return this.getBackDevices().length > 1;
        }
        return false;
    }
    pushDevice(device) {
        this.debug += "[pushDevice] start.\n";
        const isFrontDev = this.isFront(device.label);
        let devLabel = device.label;
        if (device.label == '') {
            devLabel = `Cam ${isFrontDev ? 'user' : 'env'} ${this.devices.filter((e) => e.isFront == isFrontDev).length + 1}`;
        }
        const dev = {
            isFront: isFrontDev,
            mode: (isFrontDev ? eCamShootFaceMode.USER : eCamShootFaceMode.ENVIRONMENT),
            label: devLabel,
            deviceId: device.deviceId,
            haveTorch: false
        };
        this.debug += "[pushDevice] push:" + JSON.stringify(dev) + ".\n";
        this.devices.push(dev);
    }
    hasTouch(navigator) {
        if ("maxTouchPoints" in navigator) {
            return navigator.maxTouchPoints > 0;
        }
        else if ("msMaxTouchPoints" in navigator) {
            return navigator.msMaxTouchPoints > 0;
        }
        else {
            const mQ = matchMedia?.("(pointer:coarse)");
            if (mQ?.media === "(pointer:coarse)") {
                return !!mQ.matches;
            }
            else if ("orientation" in window) {
                return true; // deprecated, but good fallback
            }
            else {
                // Only as a last resort, fall back to user agent sniffing
                const UA = navigator.userAgent;
                return /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
                    /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
            }
        }
    }
    getErrors() {
        return this.showErrors ? this.error.replace(/\n/g, "<br />") : '';
    }
    getDebugInfo() {
        return this.debugMode ? this.debug.replace(/\n/g, "<br />") : '';
    }
    getStyleConfig() {
        return `--cs-sw: ${this.screen_w}px; --cs-sh: ${this.screen_h}px; --cs-head-color: ${this.color}; --cs-item-color: ${this.color};`;
    }
    isDefault() {
        return this.type == eCamShootType.DEFAULT;
    }
    isSelfie() {
        return this.type == eCamShootType.SELFIE;
    }
    isDocument() {
        return this.type == eCamShootType.DOCFRONT || this.type == eCamShootType.DOCBACK;
    }
    isDocFront() {
        return this.type == eCamShootType.DOCFRONT;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxCamShoot, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: NgxCamShoot, isStandalone: true, selector: "ngx-cam-shoot", inputs: { config: "config", canChangeMode: "canChangeMode", type: "type", color: "color", displayTitle: "displayTitle", title: "title", showFaceMode: "showFaceMode", usePreview: "usePreview", showErrors: "showErrors", debugMode: "debugMode", btnTakeAnother: "btnTakeAnother", btnAcceptCapture: "btnAcceptCapture" }, outputs: { sendImage: "sendImage" }, host: { listeners: { "window:resize": "resize()" } }, viewQueries: [{ propertyName: "video", first: true, predicate: ["videoImage"], descendants: true }, { propertyName: "canvas", first: true, predicate: ["canvasImage"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
 <ng-container *ngIf="usePreview && displayPreview">
  <div class="cam-shoot-backdrop"></div>
  <div class="cam-shoot-preview">
    <div class="preview-dialog">
      <div class="preview-content">
        <div class="preview-image">
          <picture *ngIf="isCaptured">
            <img [src]="imageCaptured">
          </picture>
        </div>
        <div class="preview-btns">
          <button (click)="takeAnother()" [innerHTML]="btnTakeAnother"></button>
          <button (click)="sendCapture()" [innerHTML]="btnAcceptCapture"></button>
        </div>
      </div>
    </div>
  </div>
</ng-container>
<div *ngIf="modalCapture" class="cam-shoot l{{orientationDegs}}" [class.landscape2]="isMobile && isLandscape" [style]="getStyleConfig()">
  <div class="video-container">
    <div class="video-block">
      <video
        [class.show]="!isCaptured"
        [class.hide]="isCaptured"
        [class.selfie]="faceMode=='user'"
        #videoImage
        id="videocap"
        width="100%"
        autoplay
        playsinline
      ></video>
    </div>
    <canvas
        #canvasImage
        id="canvas"
    ></canvas>
  </div>
  <div class="mask">
    <div class="changing" *ngIf="isChangingDevice"><span>Loading device</span></div>
    <div *ngIf="showErrors && error.length>0" class="msgError" [innerHtml]="getErrors()" (dblclick)="error = ''"></div>
    <div *ngIf="debugMode && debug.length>0" class="msgError" [innerHtml]="getDebugInfo()" (dblclick)="debug = ''"></div>

    <div class="close-btn" (click)="close()"></div>
    <div *ngIf="displayTitle" class="head-title">{{title}} <span *ngIf="showFaceMode" [innerHTML]="faceMode=='user'?'😀':'📱'"]></span><!-- <span *ngIf="isLandscape"> (L)</span><span *ngIf="isMobile"> (M)</span> --></div>

    <div class="focus-aim" *ngIf="!isDefault()">
      <div class="selfie-aim" *ngIf="isSelfie()">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
      </div>
      <div class="doc-aim" [class.doc-front]="isDocFront()" *ngIf="isDocument()"></div>
    </div>

    <div class="config">
      <div class="btnx btn-devices" *ngIf="hasMultipleDevicesOnMode">
        <select [formControl]="device">
          <ng-container *ngFor="let c of devices">
            <option *ngIf="c.mode==faceMode" [value]="c.deviceId">{{c.label}}<span *ngIf="c.haveTorch">(🔦)</span><span *ngIf="debugMode"> - {{c.deviceId}}</span></option>
          </ng-container>
        </select>
      </div>
    </div>
    <div class="controls">
      <div class="zoom" *ngIf="canActiveZoom && !isDocument()">
        <input type="range" [formControl]="zoom" [min]="zoomConfig.min" [max]="zoomConfig.max" [step]="zoomConfig.step">
        <span [innerHTML]="getZoomPercent()"></span>
      </div>
      <button role="btn" class="btnx btn-flash" [ngClass]="{'not-available':!canUseFlash,'opaque':!canActiveFlash,'lights-on':isFlashActive}" (click)="toogleFlash()">&nbsp;</button>
      <button role="btn" class="btnx btn-shoot" (click)="takeCapture()">&nbsp;</button>
      <button role="btn" class="btnx btn-change" [ngClass]="{'opaque':devices.length==1 || isChangingDevice}" (click)="toogleMode()" *ngIf="canChangeMode">&nbsp;</button>
    </div>
  </div>
</div>
  `, isInline: true, styles: ["*,:before,:after{box-sizing:border-box}.cam-shoot-backdrop{--bs-backdrop-zindex: ;--bs-backdrop-bg: ;--bs-backdrop-opacity: ;position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000;opacity:.5}.cam-shoot-preview{display:block!important;position:fixed;top:0;left:0;z-index:1055;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0;display:flex;justify-content:center;align-items:center}.cam-shoot-preview .preview-dialog{position:relative;width:auto;margin:1.75rem;pointer-events:none;height:100%;display:flex;align-items:center}.cam-shoot-preview .preview-dialog .preview-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.175);border-radius:.5rem;outline:0;padding:.75rem}@media (min-width: 576px){.cam-shoot-preview .preview-dialog{max-width:500px;margin-right:auto;margin-left:auto}}.camera{cursor:pointer;background-color:#fff;background-image:url('data:image/svg+xml,<svg width=\"800px\" height=\"800px\" viewBox=\"0 -3 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke-width=\"0\"/><g stroke-linecap=\"round\" stroke-linejoin=\"round\"/><g><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M3 3H5.58579L8 0.58579C8.37507 0.21071 8.88378 0 9.41421 0H14.5858C15.1162 0 15.6249 0.21071 16 0.58579L18.4142 3H21C22.6569 3 24 4.34315 24 6V15C24 16.6569 22.6569 18 21 18H3C1.34315 18 0 16.6569 0 15V6C0 4.34315 1.34315 3 3 3zM15 10C15 11.6569 13.6569 13 12 13C10.3431 13 9 11.6569 9 10C9 8.3431 10.3431 7 12 7C13.6569 7 15 8.3431 15 10zM17 10C17 12.7614 14.7614 15 12 15C9.23858 15 7 12.7614 7 10C7 7.2386 9.23858 5 12 5C14.7614 5 17 7.2386 17 10z\" fill=\"%23758ca3\"/></g></svg>');background-repeat:no-repeat;background-position:center;background-size:100px;height:120px;width:100%;display:flex;border:4px dashed #000;border-radius:12px;margin:12px 0}picture>img{max-width:100%;height:auto}.preview-btns{display:grid;gap:1rem;grid-template-columns:1fr 1fr;margin-top:.4rem}.preview-btns button{border-radius:4px;padding:3px 6px;background-color:#282828;color:#fff;font-size:.8rem;border:0}.cam-shoot{height:100%;width:100%;z-index:10000001;position:fixed;inset:0;background-color:#fff;overflow-x:hidden;overflow-y:hidden!important}.cam-shoot.landscape{transform:rotate(-90deg);width:var(--cs-sh);height:var(--cs-sw);background:orange;transform-origin:top right;margin-left:calc(var(--cs-sh) * -1);margin-top:1px}.cam-shoot .video-mask,.cam-shoot .video-container,.cam-shoot .video-container .video-block{height:100%;width:100%;position:relative;display:flex}.cam-shoot .video-container{z-index:1}.cam-shoot .video-container video,.cam-shoot .video-mask video{margin-top:-50px}.cam-shoot.landscape .video-container .video-block{transition:transform .5s;transform:rotate(90deg);transform-origin:center;background-color:green}.cam-shoot.landscape .video-container .video-block video,.cam-shoot.landscape .video-mask .video-block video{width:100%;height:100%;position:absolute;left:calc(calc(var(--cs-sw)/2 - var(--cs-sh)/2) * -1);top:0}.cam-shoot:not(.landscape) .video-container video,.cam-shoot:not(.landscape) .video-mask video{object-fit:cover}.cam-shoot .video-container video.selfie,.cam-shoot .video-mask video.selfie{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.cam-shoot .video-container video.mirror,.cam-shoot .video-mask video.mirror{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}.cam-shoot .video-container canvas,.cam-shoot .video-mask canvas{display:none!important;-webkit-transform:scaleX(-1);transform:scaleX(-1)}.msgError{position:absolute;top:25%;left:5%;width:90%;border-radius:5px;background-color:red;color:#fff;padding:10px;font-size:.95rem;text-align:left;height:300px;overflow-y:scroll;opacity:.85;z-index:3;word-wrap:break-word}.cam-shoot .mask{position:absolute;top:0;left:0;display:grid;width:100%;height:100%;z-index:2;grid-auto-flow:row;grid-template-rows:auto 1fr 1fr 1fr}.cam-shoot.landscape2 .mask{width:var(--cs-sh);height:var(--cs-sw)}.cam-shoot.landscape2 .mask,.cam-shoot.landscape2.l90 .mask{transform-origin:top right;transform:rotate(-90deg);margin-left:calc(var(--cs-sh) * -1)}.cam-shoot.landscape2.l-90 .mask{transform-origin:top left;transform:rotate(90deg);margin-left:calc(var(--cs-sw) - 31px)}.cam-shoot .mask .close-btn{z-index:3;position:absolute;right:.55rem;top:.6rem;width:1.5rem;height:1.5rem;padding:1rem;border:0;border-radius:1rem;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e\");background-color:#fff;background-size:60%;background-repeat:no-repeat;background-position:center;cursor:pointer}.cam-shoot .mask .head-title{width:100%;background-color:var(--cs-head-color);color:#fff;height:50px;line-height:20px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;position:relative;z-index:2;user-select:none;-moz-user-select:none;-webkit-user-select:none}.cam-shoot .mask .changing{position:absolute;top:9%;left:0;width:100%;z-index:3;text-align:center;display:flex;justify-content:center;align-items:center}.cam-shoot .mask .changing>span{background-color:#282828;opacity:.7;color:#fff;border-radius:6px;padding:3px 8px}.cam-shoot .mask .focus-aim{position:absolute;inset:0;display:flex;align-items:start;justify-content:center}.cam-shoot .mask .focus-aim .selfie-aim{width:250px;height:250px;position:absolute;margin-top:50%;position:relative}.cam-shoot .mask .focus-aim .selfie-aim>div{position:absolute;width:75px;height:75px;border:5px solid var(--cs-item-color)}.cam-shoot .mask .focus-aim .selfie-aim>div:nth-child(1){left:0;top:0;border-right:none;border-bottom:none}.cam-shoot .mask .focus-aim .selfie-aim>div:nth-child(2){right:0;top:0;border-left:none;border-bottom:none}.cam-shoot .mask .focus-aim .selfie-aim>div:nth-child(3){left:0;bottom:0;border-right:none;border-top:none}.cam-shoot .mask .focus-aim .selfie-aim>div:nth-child(4){right:0;bottom:0;border-left:none;border-top:none}.cam-shoot .mask .focus-aim .doc-aim{position:absolute;top:23%;width:75%;height:55%;border:5px solid var(--cs-item-color);opacity:.6;border-radius:8px}.cam-shoot .mask .focus-aim .doc-aim.doc-front:before{content:\"\";position:absolute;top:0;width:150px;height:120px;border:5px solid var(--cs-item-color);right:0;margin-right:-5px;margin-top:-5px;border-top-right-radius:8px;border-bottom-left-radius:8px}.cam-shoot .mask .controls{position:absolute;width:100%;bottom:0;min-height:150px;display:flex;justify-content:center}.cam-shoot.landscape2 .mask .controls{margin-bottom:1.5rem}.cam-shoot .mask .controls .zoom{width:70%;display:flex;flex-direction:column;align-items:center}.cam-shoot .mask .controls .zoom>input[type=range]{accent-color:var(--cs-item-color)!important;width:100%;z-index:2}.cam-shoot .mask .controls .zoom>span{text-align:center;user-select:none;-moz-user-select:none;-webkit-user-select:none;background-color:var(--cs-item-color);color:#fff;border-radius:8px;padding:0 9px 0 4px;opacity:.9;display:inline-flex;width:45px;margin-top:3px;margin-left:8px}.cam-shoot .mask .controls .zoom>span:before{content:\"\\a0\"}.cam-shoot .mask .controls .zoom>span:after{content:\"x\"}.cam-shoot.landscape2 .mask .controls .zoom>span{transition:transform .5s;margin-top:7px;margin-left:0;padding:0 3px 1px}.cam-shoot.landscape2 .mask .btnx{transition:transform 1s}.cam-shoot.landscape2 .mask .btnx,.cam-shoot.landscape2 .mask .msgError,.cam-shoot.landscape2 .mask .controls .zoom>span .cam-shoot.landscape2 .mask .btnx,.cam-shoot.landscape2 .mask .controls .zoom>span{transform:rotate(90deg)}.cam-shoot.landscape2.l-90 .mask .btnx,.cam-shoot.landscape2.l-90 .mask .msgError,.cam-shoot.landscape2.l-90 .mask .controls .zoom>span{transform:rotate(-90deg)}.cam-shoot .mask .btnx{background-color:var(--cs-item-color)!important;-moz-user-select:none;display:inline-block;padding:.375rem .75;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;border:1px solid transparent;border-radius:.375rem;background-color:transparent;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:button;text-transform:none;margin:0;border-radius:0}.cam-shoot .mask .btnx:active{transform:translateY(-1px);box-shadow:0 5px 10px #0003}.cam-shoot .mask .btnx.btn-devices,.cam-shoot .mask .btnx.btn-devices>select{width:70px;height:70px;border-radius:35px}.cam-shoot .mask .btnx.btn-devices{position:absolute;top:13%;left:3%;border:none!important}.cam-shoot .mask .btnx.btn-devices>select{margin-left:-.5px;margin-top:-1px;-webkit-appearance:none;-moz-appearance:none;color:transparent;border:none!important;cursor:pointer;background-color:transparent}.cam-shoot .mask .btnx.btn-devices select::-ms-expand{display:none}.cam-shoot .mask .btnx.btn-config{position:absolute;top:13%;right:3%;width:70px;height:70px;border-radius:35px;background-image:url(\"data:image/svg+xml,%3Csvg width='800px' height='800px' viewBox='0 0 512 512' version='1.1' xml:space='preserve' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' fill='%23000000'%3E%3Cg stroke-width='0'/%3E%3Cg stroke-linecap='round' stroke-linejoin='round'/%3E%3Cg%3E%3Cg%3E%3Cpath fill='%23fff' d='M161.6,237.5c3.6-1.2,7.5-1.8,11.4-1.8c6.3,0,12.5,1.6,17.9,4.5l13.5-13.5l25.4-25.4l21.2,21.2l34.3-34.3 l-4.4-4.8c19.5-36.7,16.5-83.1-11.2-117.5c-28-34.8-73.2-47.5-113.5-35.7l64.9,80.6l-64.2,51.7L92.2,81.9 c-20.1,36.9-17.3,83.8,10.7,118.5C118.4,219.7,139.2,232.2,161.6,237.5z'/%3E%3Cpath fill='%23fff' d='M332.1,239.4L300,271.5l21.2,21.2l-37.1,37.1l-1.7,1.7L364.7,448c19.5,27.6,58.2,33,84.5,11.8 c26.3-21.2,29.3-60.1,6.5-85.1L332.1,239.4z'/%3E%3Cpath fill='%23fff' d='M263.5,330.5L263.5,330.5L192,259v0l-2.4-2.4c-9.1-9.1-23.9-9.1-33,0L43.4,369.8c-9.1,9.1-9.1,23.9,0,33 l76.4,76.4c9.1,9.1,23.9,9.1,33,0L266,366c9.1-9.1,9.1-23.9,0-33L263.5,330.5z'/%3E%3Cpath fill='%23e0e0e0' d='M471.7,110.9l-48.2,48.2c-5,5-13.2,5-18.2,0l-6.3-6.3L322.6,229l-42.5,42.4l21.2,21.2l-27.2,27.2l-0.8,0.8 l-4.1-4.1L206,253.2v0l-4.1-4.1l12.4-12.4l15.5-15.5l21.2,21.2l43.8-43.8l75-75l-6.3-6.3c-5-5.1-5-13.2,0-18.2l48.2-48.2 c5-5,13.2-5,18.2,0l41.8,41.8C476.7,97.7,476.7,105.8,471.7,110.9z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:center;background-size:50%}.cam-shoot .mask .btnx.btn-flash{position:absolute;bottom:10%;left:5%;width:70px;height:70px;border-radius:35px;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512' fill='%23fff'%3E%3Cpath d='M349.4 44.6c5.9-13.7 1.5-29.7-10.6-38.5s-28.6-8-39.9 1.8l-256 224c-10 8.8-13.6 22.9-8.9 35.3S50.7 288 64 288H175.5L98.6 467.4c-5.9 13.7-1.5 29.7 10.6 38.5s28.6 8 39.9-1.8l256-224c10-8.8 13.6-22.9 8.9-35.3s-16.6-20.7-30-20.7H272.5L349.4 44.6z'/%3E%3C/svg%3E\");background-position:50%;background-repeat:no-repeat;background-size:50%}.cam-shoot .mask .btnx.btn-flash.lights-on{background-color:gold!important}.cam-shoot .mask .btnx.btn-shoot{position:absolute;bottom:10%;left:calc(50% - 35px);width:70px;height:70px;border-radius:35px}.cam-shoot .mask .btnx.btn-change{position:absolute;bottom:10%;right:5%;width:70px;height:70px;border-radius:35px;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23fff'%3E%3Cpath d='M149.1 64.8L138.7 96H64C28.7 96 0 124.7 0 160V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H373.3L362.9 64.8C356.4 45.2 338.1 32 317.4 32H194.6c-20.7 0-39 13.2-45.5 32.8zM384 256c0 8.8-7.2 16-16 16H291.3c-6.2 0-11.3-5.1-11.3-11.3c0-3 1.2-5.9 3.3-8L307 229c-13.6-13.4-31.9-21-51-21c-19.2 0-37.7 7.6-51.3 21.3L185 249c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l19.7-19.7C193.4 172.7 224 160 256 160c31.8 0 62.4 12.6 85 35l23.7-23.7c2.1-2.1 5-3.3 8-3.3c6.2 0 11.3 5.1 11.3 11.3V256zM128 320c0-8.8 7.2-16 16-16h76.7c6.2 0 11.3 5.1 11.3 11.3c0 3-1.2 5.9-3.3 8L205 347c13.6 13.4 31.9 21 51 21c19.2 0 37.7-7.6 51.3-21.3L327 327c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-19.7 19.7C318.6 403.3 288 416 256 416c-31.8 0-62.4-12.6-85-35l-23.7 23.7c-2.1 2.1-5 3.3-8 3.3c-6.2 0-11.3-5.1-11.3-11.3V320z'/%3E%3C/svg%3E\");background-position:50%;background-repeat:no-repeat;background-size:50%}.btn-change:active{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}.cam-shoot .mask .btnx.opaque:not(.not-available){pointer-events:none;opacity:.75}.cam-shoot .mask .btnx.not-available{pointer-events:none;background-color:#979797!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxCamShoot, decorators: [{
            type: Component,
            args: [{ selector: 'ngx-cam-shoot', imports: [
                        CommonModule,
                        FormsModule,
                        ReactiveFormsModule
                    ], standalone: true, template: `
 <ng-container *ngIf="usePreview && displayPreview">
  <div class="cam-shoot-backdrop"></div>
  <div class="cam-shoot-preview">
    <div class="preview-dialog">
      <div class="preview-content">
        <div class="preview-image">
          <picture *ngIf="isCaptured">
            <img [src]="imageCaptured">
          </picture>
        </div>
        <div class="preview-btns">
          <button (click)="takeAnother()" [innerHTML]="btnTakeAnother"></button>
          <button (click)="sendCapture()" [innerHTML]="btnAcceptCapture"></button>
        </div>
      </div>
    </div>
  </div>
</ng-container>
<div *ngIf="modalCapture" class="cam-shoot l{{orientationDegs}}" [class.landscape2]="isMobile && isLandscape" [style]="getStyleConfig()">
  <div class="video-container">
    <div class="video-block">
      <video
        [class.show]="!isCaptured"
        [class.hide]="isCaptured"
        [class.selfie]="faceMode=='user'"
        #videoImage
        id="videocap"
        width="100%"
        autoplay
        playsinline
      ></video>
    </div>
    <canvas
        #canvasImage
        id="canvas"
    ></canvas>
  </div>
  <div class="mask">
    <div class="changing" *ngIf="isChangingDevice"><span>Loading device</span></div>
    <div *ngIf="showErrors && error.length>0" class="msgError" [innerHtml]="getErrors()" (dblclick)="error = ''"></div>
    <div *ngIf="debugMode && debug.length>0" class="msgError" [innerHtml]="getDebugInfo()" (dblclick)="debug = ''"></div>

    <div class="close-btn" (click)="close()"></div>
    <div *ngIf="displayTitle" class="head-title">{{title}} <span *ngIf="showFaceMode" [innerHTML]="faceMode=='user'?'😀':'📱'"]></span><!-- <span *ngIf="isLandscape"> (L)</span><span *ngIf="isMobile"> (M)</span> --></div>

    <div class="focus-aim" *ngIf="!isDefault()">
      <div class="selfie-aim" *ngIf="isSelfie()">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
      </div>
      <div class="doc-aim" [class.doc-front]="isDocFront()" *ngIf="isDocument()"></div>
    </div>

    <div class="config">
      <div class="btnx btn-devices" *ngIf="hasMultipleDevicesOnMode">
        <select [formControl]="device">
          <ng-container *ngFor="let c of devices">
            <option *ngIf="c.mode==faceMode" [value]="c.deviceId">{{c.label}}<span *ngIf="c.haveTorch">(🔦)</span><span *ngIf="debugMode"> - {{c.deviceId}}</span></option>
          </ng-container>
        </select>
      </div>
    </div>
    <div class="controls">
      <div class="zoom" *ngIf="canActiveZoom && !isDocument()">
        <input type="range" [formControl]="zoom" [min]="zoomConfig.min" [max]="zoomConfig.max" [step]="zoomConfig.step">
        <span [innerHTML]="getZoomPercent()"></span>
      </div>
      <button role="btn" class="btnx btn-flash" [ngClass]="{'not-available':!canUseFlash,'opaque':!canActiveFlash,'lights-on':isFlashActive}" (click)="toogleFlash()">&nbsp;</button>
      <button role="btn" class="btnx btn-shoot" (click)="takeCapture()">&nbsp;</button>
      <button role="btn" class="btnx btn-change" [ngClass]="{'opaque':devices.length==1 || isChangingDevice}" (click)="toogleMode()" *ngIf="canChangeMode">&nbsp;</button>
    </div>
  </div>
</div>
  `, styles: ["*,:before,:after{box-sizing:border-box}.cam-shoot-backdrop{--bs-backdrop-zindex: ;--bs-backdrop-bg: ;--bs-backdrop-opacity: ;position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000;opacity:.5}.cam-shoot-preview{display:block!important;position:fixed;top:0;left:0;z-index:1055;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0;display:flex;justify-content:center;align-items:center}.cam-shoot-preview .preview-dialog{position:relative;width:auto;margin:1.75rem;pointer-events:none;height:100%;display:flex;align-items:center}.cam-shoot-preview .preview-dialog .preview-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.175);border-radius:.5rem;outline:0;padding:.75rem}@media (min-width: 576px){.cam-shoot-preview .preview-dialog{max-width:500px;margin-right:auto;margin-left:auto}}.camera{cursor:pointer;background-color:#fff;background-image:url('data:image/svg+xml,<svg width=\"800px\" height=\"800px\" viewBox=\"0 -3 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke-width=\"0\"/><g stroke-linecap=\"round\" stroke-linejoin=\"round\"/><g><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M3 3H5.58579L8 0.58579C8.37507 0.21071 8.88378 0 9.41421 0H14.5858C15.1162 0 15.6249 0.21071 16 0.58579L18.4142 3H21C22.6569 3 24 4.34315 24 6V15C24 16.6569 22.6569 18 21 18H3C1.34315 18 0 16.6569 0 15V6C0 4.34315 1.34315 3 3 3zM15 10C15 11.6569 13.6569 13 12 13C10.3431 13 9 11.6569 9 10C9 8.3431 10.3431 7 12 7C13.6569 7 15 8.3431 15 10zM17 10C17 12.7614 14.7614 15 12 15C9.23858 15 7 12.7614 7 10C7 7.2386 9.23858 5 12 5C14.7614 5 17 7.2386 17 10z\" fill=\"%23758ca3\"/></g></svg>');background-repeat:no-repeat;background-position:center;background-size:100px;height:120px;width:100%;display:flex;border:4px dashed #000;border-radius:12px;margin:12px 0}picture>img{max-width:100%;height:auto}.preview-btns{display:grid;gap:1rem;grid-template-columns:1fr 1fr;margin-top:.4rem}.preview-btns button{border-radius:4px;padding:3px 6px;background-color:#282828;color:#fff;font-size:.8rem;border:0}.cam-shoot{height:100%;width:100%;z-index:10000001;position:fixed;inset:0;background-color:#fff;overflow-x:hidden;overflow-y:hidden!important}.cam-shoot.landscape{transform:rotate(-90deg);width:var(--cs-sh);height:var(--cs-sw);background:orange;transform-origin:top right;margin-left:calc(var(--cs-sh) * -1);margin-top:1px}.cam-shoot .video-mask,.cam-shoot .video-container,.cam-shoot .video-container .video-block{height:100%;width:100%;position:relative;display:flex}.cam-shoot .video-container{z-index:1}.cam-shoot .video-container video,.cam-shoot .video-mask video{margin-top:-50px}.cam-shoot.landscape .video-container .video-block{transition:transform .5s;transform:rotate(90deg);transform-origin:center;background-color:green}.cam-shoot.landscape .video-container .video-block video,.cam-shoot.landscape .video-mask .video-block video{width:100%;height:100%;position:absolute;left:calc(calc(var(--cs-sw)/2 - var(--cs-sh)/2) * -1);top:0}.cam-shoot:not(.landscape) .video-container video,.cam-shoot:not(.landscape) .video-mask video{object-fit:cover}.cam-shoot .video-container video.selfie,.cam-shoot .video-mask video.selfie{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.cam-shoot .video-container video.mirror,.cam-shoot .video-mask video.mirror{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}.cam-shoot .video-container canvas,.cam-shoot .video-mask canvas{display:none!important;-webkit-transform:scaleX(-1);transform:scaleX(-1)}.msgError{position:absolute;top:25%;left:5%;width:90%;border-radius:5px;background-color:red;color:#fff;padding:10px;font-size:.95rem;text-align:left;height:300px;overflow-y:scroll;opacity:.85;z-index:3;word-wrap:break-word}.cam-shoot .mask{position:absolute;top:0;left:0;display:grid;width:100%;height:100%;z-index:2;grid-auto-flow:row;grid-template-rows:auto 1fr 1fr 1fr}.cam-shoot.landscape2 .mask{width:var(--cs-sh);height:var(--cs-sw)}.cam-shoot.landscape2 .mask,.cam-shoot.landscape2.l90 .mask{transform-origin:top right;transform:rotate(-90deg);margin-left:calc(var(--cs-sh) * -1)}.cam-shoot.landscape2.l-90 .mask{transform-origin:top left;transform:rotate(90deg);margin-left:calc(var(--cs-sw) - 31px)}.cam-shoot .mask .close-btn{z-index:3;position:absolute;right:.55rem;top:.6rem;width:1.5rem;height:1.5rem;padding:1rem;border:0;border-radius:1rem;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e\");background-color:#fff;background-size:60%;background-repeat:no-repeat;background-position:center;cursor:pointer}.cam-shoot .mask .head-title{width:100%;background-color:var(--cs-head-color);color:#fff;height:50px;line-height:20px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;position:relative;z-index:2;user-select:none;-moz-user-select:none;-webkit-user-select:none}.cam-shoot .mask .changing{position:absolute;top:9%;left:0;width:100%;z-index:3;text-align:center;display:flex;justify-content:center;align-items:center}.cam-shoot .mask .changing>span{background-color:#282828;opacity:.7;color:#fff;border-radius:6px;padding:3px 8px}.cam-shoot .mask .focus-aim{position:absolute;inset:0;display:flex;align-items:start;justify-content:center}.cam-shoot .mask .focus-aim .selfie-aim{width:250px;height:250px;position:absolute;margin-top:50%;position:relative}.cam-shoot .mask .focus-aim .selfie-aim>div{position:absolute;width:75px;height:75px;border:5px solid var(--cs-item-color)}.cam-shoot .mask .focus-aim .selfie-aim>div:nth-child(1){left:0;top:0;border-right:none;border-bottom:none}.cam-shoot .mask .focus-aim .selfie-aim>div:nth-child(2){right:0;top:0;border-left:none;border-bottom:none}.cam-shoot .mask .focus-aim .selfie-aim>div:nth-child(3){left:0;bottom:0;border-right:none;border-top:none}.cam-shoot .mask .focus-aim .selfie-aim>div:nth-child(4){right:0;bottom:0;border-left:none;border-top:none}.cam-shoot .mask .focus-aim .doc-aim{position:absolute;top:23%;width:75%;height:55%;border:5px solid var(--cs-item-color);opacity:.6;border-radius:8px}.cam-shoot .mask .focus-aim .doc-aim.doc-front:before{content:\"\";position:absolute;top:0;width:150px;height:120px;border:5px solid var(--cs-item-color);right:0;margin-right:-5px;margin-top:-5px;border-top-right-radius:8px;border-bottom-left-radius:8px}.cam-shoot .mask .controls{position:absolute;width:100%;bottom:0;min-height:150px;display:flex;justify-content:center}.cam-shoot.landscape2 .mask .controls{margin-bottom:1.5rem}.cam-shoot .mask .controls .zoom{width:70%;display:flex;flex-direction:column;align-items:center}.cam-shoot .mask .controls .zoom>input[type=range]{accent-color:var(--cs-item-color)!important;width:100%;z-index:2}.cam-shoot .mask .controls .zoom>span{text-align:center;user-select:none;-moz-user-select:none;-webkit-user-select:none;background-color:var(--cs-item-color);color:#fff;border-radius:8px;padding:0 9px 0 4px;opacity:.9;display:inline-flex;width:45px;margin-top:3px;margin-left:8px}.cam-shoot .mask .controls .zoom>span:before{content:\"\\a0\"}.cam-shoot .mask .controls .zoom>span:after{content:\"x\"}.cam-shoot.landscape2 .mask .controls .zoom>span{transition:transform .5s;margin-top:7px;margin-left:0;padding:0 3px 1px}.cam-shoot.landscape2 .mask .btnx{transition:transform 1s}.cam-shoot.landscape2 .mask .btnx,.cam-shoot.landscape2 .mask .msgError,.cam-shoot.landscape2 .mask .controls .zoom>span .cam-shoot.landscape2 .mask .btnx,.cam-shoot.landscape2 .mask .controls .zoom>span{transform:rotate(90deg)}.cam-shoot.landscape2.l-90 .mask .btnx,.cam-shoot.landscape2.l-90 .mask .msgError,.cam-shoot.landscape2.l-90 .mask .controls .zoom>span{transform:rotate(-90deg)}.cam-shoot .mask .btnx{background-color:var(--cs-item-color)!important;-moz-user-select:none;display:inline-block;padding:.375rem .75;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;border:1px solid transparent;border-radius:.375rem;background-color:transparent;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:button;text-transform:none;margin:0;border-radius:0}.cam-shoot .mask .btnx:active{transform:translateY(-1px);box-shadow:0 5px 10px #0003}.cam-shoot .mask .btnx.btn-devices,.cam-shoot .mask .btnx.btn-devices>select{width:70px;height:70px;border-radius:35px}.cam-shoot .mask .btnx.btn-devices{position:absolute;top:13%;left:3%;border:none!important}.cam-shoot .mask .btnx.btn-devices>select{margin-left:-.5px;margin-top:-1px;-webkit-appearance:none;-moz-appearance:none;color:transparent;border:none!important;cursor:pointer;background-color:transparent}.cam-shoot .mask .btnx.btn-devices select::-ms-expand{display:none}.cam-shoot .mask .btnx.btn-config{position:absolute;top:13%;right:3%;width:70px;height:70px;border-radius:35px;background-image:url(\"data:image/svg+xml,%3Csvg width='800px' height='800px' viewBox='0 0 512 512' version='1.1' xml:space='preserve' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' fill='%23000000'%3E%3Cg stroke-width='0'/%3E%3Cg stroke-linecap='round' stroke-linejoin='round'/%3E%3Cg%3E%3Cg%3E%3Cpath fill='%23fff' d='M161.6,237.5c3.6-1.2,7.5-1.8,11.4-1.8c6.3,0,12.5,1.6,17.9,4.5l13.5-13.5l25.4-25.4l21.2,21.2l34.3-34.3 l-4.4-4.8c19.5-36.7,16.5-83.1-11.2-117.5c-28-34.8-73.2-47.5-113.5-35.7l64.9,80.6l-64.2,51.7L92.2,81.9 c-20.1,36.9-17.3,83.8,10.7,118.5C118.4,219.7,139.2,232.2,161.6,237.5z'/%3E%3Cpath fill='%23fff' d='M332.1,239.4L300,271.5l21.2,21.2l-37.1,37.1l-1.7,1.7L364.7,448c19.5,27.6,58.2,33,84.5,11.8 c26.3-21.2,29.3-60.1,6.5-85.1L332.1,239.4z'/%3E%3Cpath fill='%23fff' d='M263.5,330.5L263.5,330.5L192,259v0l-2.4-2.4c-9.1-9.1-23.9-9.1-33,0L43.4,369.8c-9.1,9.1-9.1,23.9,0,33 l76.4,76.4c9.1,9.1,23.9,9.1,33,0L266,366c9.1-9.1,9.1-23.9,0-33L263.5,330.5z'/%3E%3Cpath fill='%23e0e0e0' d='M471.7,110.9l-48.2,48.2c-5,5-13.2,5-18.2,0l-6.3-6.3L322.6,229l-42.5,42.4l21.2,21.2l-27.2,27.2l-0.8,0.8 l-4.1-4.1L206,253.2v0l-4.1-4.1l12.4-12.4l15.5-15.5l21.2,21.2l43.8-43.8l75-75l-6.3-6.3c-5-5.1-5-13.2,0-18.2l48.2-48.2 c5-5,13.2-5,18.2,0l41.8,41.8C476.7,97.7,476.7,105.8,471.7,110.9z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:center;background-size:50%}.cam-shoot .mask .btnx.btn-flash{position:absolute;bottom:10%;left:5%;width:70px;height:70px;border-radius:35px;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512' fill='%23fff'%3E%3Cpath d='M349.4 44.6c5.9-13.7 1.5-29.7-10.6-38.5s-28.6-8-39.9 1.8l-256 224c-10 8.8-13.6 22.9-8.9 35.3S50.7 288 64 288H175.5L98.6 467.4c-5.9 13.7-1.5 29.7 10.6 38.5s28.6 8 39.9-1.8l256-224c10-8.8 13.6-22.9 8.9-35.3s-16.6-20.7-30-20.7H272.5L349.4 44.6z'/%3E%3C/svg%3E\");background-position:50%;background-repeat:no-repeat;background-size:50%}.cam-shoot .mask .btnx.btn-flash.lights-on{background-color:gold!important}.cam-shoot .mask .btnx.btn-shoot{position:absolute;bottom:10%;left:calc(50% - 35px);width:70px;height:70px;border-radius:35px}.cam-shoot .mask .btnx.btn-change{position:absolute;bottom:10%;right:5%;width:70px;height:70px;border-radius:35px;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23fff'%3E%3Cpath d='M149.1 64.8L138.7 96H64C28.7 96 0 124.7 0 160V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H373.3L362.9 64.8C356.4 45.2 338.1 32 317.4 32H194.6c-20.7 0-39 13.2-45.5 32.8zM384 256c0 8.8-7.2 16-16 16H291.3c-6.2 0-11.3-5.1-11.3-11.3c0-3 1.2-5.9 3.3-8L307 229c-13.6-13.4-31.9-21-51-21c-19.2 0-37.7 7.6-51.3 21.3L185 249c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l19.7-19.7C193.4 172.7 224 160 256 160c31.8 0 62.4 12.6 85 35l23.7-23.7c2.1-2.1 5-3.3 8-3.3c6.2 0 11.3 5.1 11.3 11.3V256zM128 320c0-8.8 7.2-16 16-16h76.7c6.2 0 11.3 5.1 11.3 11.3c0 3-1.2 5.9-3.3 8L205 347c13.6 13.4 31.9 21 51 21c19.2 0 37.7-7.6 51.3-21.3L327 327c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-19.7 19.7C318.6 403.3 288 416 256 416c-31.8 0-62.4-12.6-85-35l-23.7 23.7c-2.1 2.1-5 3.3-8 3.3c-6.2 0-11.3-5.1-11.3-11.3V320z'/%3E%3C/svg%3E\");background-position:50%;background-repeat:no-repeat;background-size:50%}.btn-change:active{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}.cam-shoot .mask .btnx.opaque:not(.not-available){pointer-events:none;opacity:.75}.cam-shoot .mask .btnx.not-available{pointer-events:none;background-color:#979797!important}\n"] }]
        }], ctorParameters: () => [], propDecorators: { sendImage: [{
                type: Output
            }], video: [{
                type: ViewChild,
                args: ["videoImage"]
            }], canvas: [{
                type: ViewChild,
                args: ["canvasImage"]
            }], config: [{
                type: Input
            }], canChangeMode: [{
                type: Input
            }], type: [{
                type: Input
            }], color: [{
                type: Input
            }], displayTitle: [{
                type: Input
            }], title: [{
                type: Input
            }], showFaceMode: [{
                type: Input
            }], usePreview: [{
                type: Input
            }], showErrors: [{
                type: Input
            }], debugMode: [{
                type: Input
            }], btnTakeAnother: [{
                type: Input
            }], btnAcceptCapture: [{
                type: Input
            }], resize: [{
                type: HostListener,
                args: ['window:resize']
            }] } });

/*
 * Public API Surface of ngx-cam-shoot
 */

/**
 * Generated bundle index. Do not edit.
 */

export { NgxCamShoot, eCamShootFaceMode, eCamShootType };
//# sourceMappingURL=ngx-cam-shoot.mjs.map