web-dev-qa-db-fra.com

Comment dessiner une photo avec une orientation correcte sur la toile après la capture d'une photo en utilisant l'entrée [type = 'fichier'] dans le navigateur Web mobile?

Je crée une application Web simple dans mobile qui permet au visiteur de capturer une photo en utilisant l'élément html5 input [type = file]. Ensuite, je vais l'afficher sur le Web pour la prévisualisation, puis le visiteur peut choisir de télécharger la photo sur mon serveur à d'autres fins (par exemple: télécharger au format FB)

Je trouve un problème d'orientation de la photo lorsque je prends une photo à l'aide de mon iPhone et que je la tiens à la verticale. La photo est correctement orientée. Cependant, lorsque j'essaie de le dessiner dans la zone de dessin à l'aide de la méthode drawImage (), il est dessiné pivoté à 90 degrés.

J'ai essayé de prendre une photo dans 4 orientations, une seule d'entre elles peut dessiner une image correcte dans la toile, les autres sont pivotées ou même retournées.

Eh bien, je suis confus d’obtenir la bonne orientation pour résoudre ce problème ... Merci de votre aide ...

voici mon code, surtout une copie de MDN

<div class="container">
            <h1>Camera API</h1>

            <section class="main-content">
                <p>A demo of the Camera API, currently implemented in Firefox and Google Chrome on Android. Choose to take a picture with your device's camera and a preview will be shown through createObjectURL or a FileReader object (choosing local files supported too).</p>

                <p>
                    <form method="post" enctype="multipart/form-data" action="index.php">
                        <input type="file" id="take-picture" name="image" accept="image/*">
                        <input type="hidden" name="action" value="submit">
                        <input type="submit" >
                    </form>
                </p>

                <h2>Preview:</h2>
                <div style="width:100%;max-width:320px;">
                    <img src="about:blank" alt="" id="show-picture" width="100%">
                </div>

                <p id="error"></p>
                <canvas id="c" width="640" height="480"></canvas>
            </section>

        </div>


        <script>
            (function () {
                var takePicture = document.querySelector("#take-picture"),
                    showPicture = document.querySelector("#show-picture");

                if (takePicture && showPicture) {
                    // Set events
                    takePicture.onchange = function (event) {
                        showPicture.onload = function(){
                            var canvas = document.querySelector("#c");
                            var ctx = canvas.getContext("2d");
                            ctx.drawImage(showPicture,0,0,showPicture.width,showPicture.height);
                        }
                        // Get a reference to the taken picture or chosen file
                        var files = event.target.files,
                            file;
                        if (files && files.length > 0) {
                            file = files[0];
                            try {
                                // Get window.URL object
                                var URL = window.URL || window.webkitURL;

                                // Create ObjectURL
                                var imgURL = URL.createObjectURL(file);

                                // Set img src to ObjectURL
                                showPicture.src = imgURL;

                                // Revoke ObjectURL
                                URL.revokeObjectURL(imgURL);
                            }
                            catch (e) {
                                try {
                                    // Fallback if createObjectURL is not supported
                                    var fileReader = new FileReader();
                                    fileReader.onload = function (event) {
                                        showPicture.src = event.target.result;

                                    };
                                    fileReader.readAsDataURL(file);
                                }
                                catch (e) {
                                    // Display error message
                                    var error = document.querySelector("#error");
                                    if (error) {
                                        error.innerHTML = "Neither createObjectURL or FileReader are supported";
                                    }
                                }
                            }
                        }
                    };
                }
            })();
        </script>
64
Rock Yip

Vous devrez lire les données exif et vérifier si exif.Orientation est l’un des suivants:

fileReader.onloadend = function() {

    var exif = EXIF.readFromBinaryFile(new BinaryFile(this.result));

    switch(exif.Orientation){

       case 8:
           ctx.rotate(90*Math.PI/180);
           break;
       case 3:
           ctx.rotate(180*Math.PI/180);
           break;
       case 6:
           ctx.rotate(-90*Math.PI/180);
           break;


    }
};
45
Ben Wong

La réponse de Ben m'a bien orientée, mais pour autant que je sache, les rotations sont incorrectes (du moins elles l'ont été pour moi) et ne couvrent pas tous les cas possibles. La solution ci-dessous a fonctionné pour moi. Il est basé sur celui trouvé dans la bibliothèque JavaScript-Load-Image (que j'ai trouvée via this great SO question ). Note que je devais également traduire le contexte Canvas au centre car il provient du coin supérieur gauche lors de la rotation).

fileReader.onloadend = function() {

    var exif = EXIF.readFromBinaryFile(new BinaryFile(this.result));

    switch(exif.Orientation){

        case 2:
            // horizontal flip
            ctx.translate(canvas.width, 0);
            ctx.scale(-1, 1);
            break;
        case 3:
            // 180° rotate left
            ctx.translate(canvas.width, canvas.height);
            ctx.rotate(Math.PI);
            break;
        case 4:
            // vertical flip
            ctx.translate(0, canvas.height);
            ctx.scale(1, -1);
            break;
        case 5:
            // vertical flip + 90 rotate right
            ctx.rotate(0.5 * Math.PI);
            ctx.scale(1, -1);
            break;
        case 6:
            // 90° rotate right
            ctx.rotate(0.5 * Math.PI);
            ctx.translate(0, -canvas.height);
            break;
        case 7:
            // horizontal flip + 90 rotate right
            ctx.rotate(0.5 * Math.PI);
            ctx.translate(canvas.width, -canvas.height);
            ctx.scale(-1, 1);
            break;
        case 8:
            // 90° rotate left
            ctx.rotate(-0.5 * Math.PI);
            ctx.translate(-canvas.width, 0);
            break;


    }
};
42
gburning

ajoutez exif.js à votre projet, puis:

EXIF.getData(file,function() {
  var orientation = EXIF.getTag(this,"Orientation");
  var can = document.createElement("canvas");
  var ctx = can.getContext('2d');
  var thisImage = new Image;
  thisImage.onload = function() {
    can.width  = thisImage.width;
    can.height = thisImage.height;
    ctx.save();
    var width  = can.width;  var styleWidth  = can.style.width;
    var height = can.height; var styleHeight = can.style.height;
    if (orientation) {
      if (orientation > 4) {
        can.width  = height; can.style.width  = styleHeight;
        can.height = width;  can.style.height = styleWidth;
      }
      switch (orientation) {
      case 2: ctx.translate(width, 0);     ctx.scale(-1,1); break;
      case 3: ctx.translate(width,height); ctx.rotate(Math.PI); break;
      case 4: ctx.translate(0,height);     ctx.scale(1,-1); break;
      case 5: ctx.rotate(0.5 * Math.PI);   ctx.scale(1,-1); break;
      case 6: ctx.rotate(0.5 * Math.PI);   ctx.translate(0,-height); break;
      case 7: ctx.rotate(0.5 * Math.PI);   ctx.translate(width,-height); ctx.scale(-1,1); break;
      case 8: ctx.rotate(-0.5 * Math.PI);  ctx.translate(-width,0); break;
      }
    }

    ctx.drawImage(thisImage,0,0);
    ctx.restore();
    var dataURL = can.toDataURL();

    // at this point you can save the image away to your back-end using 'dataURL'
  }

  // now trigger the onload function by setting the src to your HTML5 file object (called 'file' here)
  thisImage.src = URL.createObjectURL(file);

});

Le bloc d’orientation (en utilisant translations et rotation) est copié à partir de https://github.com/blueimp/JavaScript-Load-Image/blob/master/js/load-image-orientation.js et ainsi de suite. Je considère que c'est bien prouvé. Cela a certainement fonctionné parfaitement pour moi, contrairement aux autres approches.

21
Andy Lorenz

Si vous voulez juste la balise Orientation, utilisez exif.js :

EXIF.getData(file, function () {
    alert(this.exifdata.Orientation);
});

Dans mes tests, l'appareil photo iOS ne renvoie que 1,3,6 ou 8.

4
Felix Turner

Sur la base de vos réponses, j'ai créé une fonction permettant de faire pivoter automatiquement l'iPhone photo dans la bonne direction.
Il suffit de passer un input.files [0] et une largeur ou hauteur maximale optionnelle, il générera un blob utilisé pour la soumission du formulaire.
https://github.com/gonnavis/iphone_photo_rotation_adjust

0
gonnavis