Moin moin und hallo,

im folgenden Artikel möchte ich die Progressive Web App Reihe um das Schießen von Fotos erweitern.


Progressive Web App Fotos

Ich möchte ein weiteres Mal das Thema PWA mehr vertiefen. In diesem Artikel werde ich zeigen, wie man mit dem Smartphone Fotos schießen und gleich abbilden kann.

Hier muss man außerdem drauf achten, dass die Desktop-Nutzer nicht ausgegrenz werden, d.h. es muss möglich sein ein ebstehendes Foto hoch zu laden.

Wie nimmt man ein Foto auf?

Wie man ein Upload-Button definiert, ist nichts außergewöhnliches, weshalb ich in diesen Punkt, neben dem Codeschnipsel unten, nicht weiter erläutern werde.

    <input type="file" name="foto">

Dieses würde auch genauso auf einem mobilen gerät funktionieren, allerdings kann der Nutzer dann nur ein bereits geschossenes Foto oder eine andere Datei für einen Upload auswählen.

Kann man das denn nicht auf ein Foto einschränken? Ja, das geht!

Dazu muss man eine neue Eigenschaft “accept” definieren, die den Medientyp genauer spezifiziert.

    <input type="file" accept="image/*;capture=camera">

Hier Klicken um es aus zu probieren

Um Videos oder Audio auf zu zeichen muss man übrigens lediglich das “accept” umdefinieren.

    <!-- Videos aufzeichnen -->
    <input type="file" accept="video/*;capture=camcorder">

    <!-- Audio aufzeichnen -->
    <input type="file" accept="audio/*;capture=microphone">

Was ist aber wenn man die Fotos direkt im Client verarbeiten möchte? Um z.B. Elemente ein zu kreisen.

Das ist mit dem Input-Element allein nicht zu machen.

Ähnlich wie in meinem Audio-Aufnahme Artikel, muss die “getUserMedia()” Funktion von “navigator.mediaDevices” genutzt werden.

Für die Verarbeitung nutzen wir einen kleinen Trick. Denn das Bild was wir mit der Video-Kamera aufzeichnen muss zum Zeitpunkt X, an dem der Nutzer das BIld schießen möchte, in ein Standbild und dann in einen Bildatensatz konvertiert werden. Das machen wir mit Hilfe einer ansonsten unsichtbaren Canvas.

Wir starten also zu Beginn die Videoaufnahme und zeichnen diese in ein Video-Element um zu sehen was wir fotografieren.

Wenn die gewünschte Bildeinstellung gefunden wurde, wird dannd as aktuelle Standbild mit den beschriebenen Trick von der Canvas an ein Img-Element übermittelt und anschließend dargestellt.

Sollte man das Bild Vorher bearbeiten möchten, muss dies natürlich in der Canvas geschehen. Das Img-Element dient nur als Abbildung des finalen Ergebnis.

Da wir die anderen Nutzer nicht ausschließen möchten, blenden wir im Falle, das das Gerät keinen Kamerazugriff ermöglicht, den Datei-Upload-Button ein.

Das vollständige Code-Schnipsel sieht wie folgt aus.


    <video autoplay id="preview-video"></video>
    <img id="foto-img" src="">
    <canvas id="convert-canvas" style="display:none;"></canvas>
    <button id="screenshot-button">Foto aufnehmen</button>
    <button id="capture-button">Foto schießen</button>
    <input id="file-selection" type="file" accept="image/*;capture=camera" style="display:none;">

    <script>
        const captureVideoButton = document.querySelector('#capture-button');
        const screenshotButton = document.querySelector('#screenshot-button');
        const img = document.querySelector('#foto-img');
        const video = document.querySelector('#preview-video');
        const canvas = document.querySelector('#convert-canvas');
        const fileSelection = document.querySelector('#file-selection');

        const cameraConstraints = {
          video: {width: {min: 1280}, height: {min: 720}}
        };

        function handleSuccess(stream) {
          //Wenn die Kamera erfolgreich gestartet worden ist, dann wird der Video-Container für die aktuelle Camera-Vorschau aktiviert
          screenshotButton.disabled = false;
          video.srcObject = stream;
        }

        function handleError(err) { 
            console.log(err);
            alert("Das Foto konnte leider nciht aufgneommen werden!");
        }

        //Starte Fotoaufnahme
        captureVideoButton.onclick = function() {

            navigator.mediaDevices.getUserMedia(cameraConstraints)
            .then(handleSuccess)
            .catch(handleError);
        }

        //Foto schießen und in der Vorschau-Canvas zeichen
        screenshotButton.onclick = video.onclick = function() {
          //Die Cancvas wir dauf die Größe des Videos skaliert
          canvas.width = video.videoWidth;
          canvas.height = video.videoHeight;

          //Das aktuelle Videobild wird als 2D Bild in die Canvas gezeichnet
          canvas.getContext('2d').drawImage(video, 0, 0);

          // Das Bild der Canvas wird in einen Datensatz konvertiert und in dem Vorschau-Bild abgebildet
          img.src = canvas.toDataURL('image/webp');

        };

        function hasGetUserMedia() {
            return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
        }

        //Wenn der Browser kein Foto schießen kann, dann zeigen wir den Datei-Upload-Button
        if (!hasGetUserMedia()) {
            fileSelection.style.display = "block";
            video.style.display = "none";
            captureVideoButton.style.display = "none";
            screenshotButton.style.display = "none";
            img.style.display = "none";
        }

    </script>

Das Ganze kann hier ausprobiert werden

Fazit

Auf die Bildbearbeitung selbst werde ich vielleicht in einem späteren Artikel eingehen.

Wie man oben sehen konnte ist das aufnehmen von Fotos, Videos oder auf Audio nicht länger nur rein nativen Apps vorbehalten.

Wichtig bei PWA ist aber auch weiterhin auch die Geräte nicht zu vernachlässigen, die nicht über Kamera und Co. verfügen.

Zwar dominiert der mobile Browser-Anteil die Gesamtkommunikation, die Desktop und Notebook Nutzer machen aber weiterhin einen großen Teil des Markts aus.

“Mobile und Offline” first aber noch nicht ausschließlich.

Wichtig

Alle Arbeiten, die etwas mit den Worker zu tun haben, funktionieren nur entweder in einer lokalen Umgebung (localhost) oder nur wenn eine gesichterte Verbindung (SSL) vorliegt.


#### In diesem Sinne, bis demnächst!