Usare la fotocamera con ExtJS

Accesso alla fotocamera

Anche se con HTML5 è stata introdotta la possibilità di accedere a gran parte dell'hardware del dispositivo, scattare una foto da un'applicazione WEB può essere una operazione piuttosto complicata. Ci sono infatti numerosi parametri da tenere in considerazione, tra cui anche problemi di permessi (da richiede all'utente), differenza tra vari dispositivi e non ultima lo stato di alcune API (es. ImageCapture è ancora considerata "Experimental" ).

In questo articolo useremo un approccio alternativo che ci permettere di ignorare tutti i problemi elencati in precedenza delegando lo scatto della foto all'applicazione di sistema. Di contro perderemo completamente la possibilità di impostare le opzioni relative allo scatto (risoluzione, aspect ratio, ecc.)

Scattare la foto

Quello che andremo a fare è semplicemente utilizzare la funzione di upload predefinita del browser. Infatti creando un tag INPUT e andando a specificare che ci interessano solo le immagini il browser mobile chiederà all'utente se leggere l'immagine dalla galleria o scattare una nuova foto. L'idea è quella di creare al volo il tag INPUT e simularne il click:

    // Tutto il codice è riferito a ExtJS 7.7 con toolkit modern
    // ma può essere facilmente adattato a qualsiasi versione
    const fileInput = Ext.dom.Helper.createDom({ 
        tag: 'input', 
        type: 'file', 
        // Questo indica che vogliamo solo delle immagini
        accept: 'image/*' 
    });
    fileInput.click();

Upload

Visualizzare l'anteprima

Una volta che l'utente ha scattato la foto possiamo visualizzarne una anteprima usando il componente Ext.Img (è anche possibile usare direttamente Ext.Component con un tag IMG). Per farlo dobbiamo agganciare un evento change al tag INPUT creato in precedenza:

    // recupera un riferimento al componente Ext.Img
    const pic = this.lookup('preview');  
    // Codice dello snippet precedente...
    const fileInput = ....;
    // Aggancia l'evento change
    fileInput.addEventListener('change', () => {
        // L'oggetto fileInput prevede la selezione multipla
        // ma siccome non la stiamo usando prendiamo il primo file
        if (fileInput.files && fileInput.files[0]) {          
            // Per trasferire l'immagine dal fileInput al tag IMG
            // usiamo la classe JavaScript FileReader
            let reader = new FileReader();

            // Visto che la lettura tramite readAsDataURL è asincrona
            // usiamo l'evento onload per assicurarci che sia terminata
            reader.onload = function(e) {
                pic.setSrc(e.target.result);
            };
            reader.readAsDataURL(fileInput.files[0]);
        }
    });

Upload sul server

A questo punto, una volta caricata l'immagine e visualizzata l'anteprima, è possibile eseguire l'upload sul server. Per farlo useremo l'oggetto JavaScript FormData sul quale possiamo caricare oltre all'immagine una serie di campi che ci interessa spedire al server.

La form può successivamente essere spedita usando Ext.Ajax:

    const formData = new FormData();
    // Uno o più campi custom che ci interessa inviare al server
    formData.append('customData', customData);
    // Volendo possiamo inviare il nome del file
    formData.append('filename', fileInput.files[0].name);
    // In questo modo inseriamo il file nella form
    formData.append('content', fileInput.files[0]);
    
    // Esegue la chiamata Ajax
    Ext.Ajax.request({
        url: '/api/upload',
        rawData: formData,
        headers: {
            // Fa in modo di usare Content-Type dell'oggetto FormData
            'Content-Type': null
        }
    });

Conclusioni

Come detto in precedenza ci sono altri modi per fare la stessa cosa avendo in più il pieno controllo dello scatto, ma quello presentato è sicuramente il più semplice.

È possibile vedere l'esempio completo su Sencha fiddle.