Js Orientation de L'Exif côté Client: images JPEG en rotation et en miroir

les photos d'appareil photo numériques sont souvent enregistrées en JPEG avec une étiquette "orientation" EXIF. Pour afficher correctement, les images doivent être tournées/miroirs en fonction de l'orientation définie, mais les navigateurs ignorent cette information qui rend l'image. Même dans les grandes applications web commerciales, la prise en charge de l'orientation EXIF peut être inégale 1 . La même source fournit également un résumé agréable de la 8 orientations différentes un JPEG peut avoir:

Summary of EXIF Orientations

des Échantillons d'images sont disponibles sur la page 4 .

la question Est de savoir comment faire pivoter/miroir l'image du côté du client afin qu'elle s'affiche correctement et puisse être traitée ultérieurement si nécessaire.

il existe des bibliothèques JS disponibles pour analyser les données EXIF, y compris l'attribut d'orientation 2 . Flickr a noté possible problème de performance lors de l'analyse d'images de grande taille, exigeant l'utilisation des web workers 3 .

les outils de Console peuvent correctement réorienter les images 5 . Un script PHP résolvant le problème est disponible à 6

99
demandé sur flexponsive 2013-12-16 02:41:21

9 réponses

Le projet github JavaScript-Charge-Image fournit une solution complète pour l'orientation EXIF problème, correctement rotation/mise en miroir des images pour tous les 8 exif orientations. Voir la démo en ligne de JavaScript orientation

l'image est dessinée sur une toile HTML5. Son rendu correct est implémenté dans js/load-image-orientation.js par des opérations sur toile.

Espère que cela sauve quelqu'un d'autre peu de temps, et enseigne les moteurs de recherche sur l'open source bijou :)

112
répondu flexponsive 2013-12-15 22:41:21

la transformation de contexte de Mederr fonctionne parfaitement. Si vous devez extraire orientation seulement utiliser cette fonction - vous n'avez pas besoin de libs de lecture EXIF. Ci-dessous se trouve une fonction pour re-définir l'orientation dans l'image de base64. voici un violon pour lui . J'ai aussi préparé un violon avec une démo d'extraction d'orientation .

function resetOrientation(srcBase64, srcOrientation, callback) {
  var img = new Image();    

  img.onload = function() {
    var width = img.width,
        height = img.height,
        canvas = document.createElement('canvas'),
        ctx = canvas.getContext("2d");

    // set proper canvas dimensions before transform & export
    if (4 < srcOrientation && srcOrientation < 9) {
      canvas.width = height;
      canvas.height = width;
    } else {
      canvas.width = width;
      canvas.height = height;
    }

    // transform context before drawing image
    switch (srcOrientation) {
      case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
      case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
      case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
      case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
      case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
      case 7: ctx.transform(0, -1, -1, 0, height, width); break;
      case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
      default: break;
    }

    // draw image
    ctx.drawImage(img, 0, 0);

    // export base64
    callback(canvas.toDataURL());
  };

  img.src = srcBase64;
};
57
répondu WunderBart 2018-07-25 16:46:54

si

width = img.width;
height = img.height;
var ctx = canvas.getContext('2d');

alors vous pouvez utiliser ces transformations pour transformer l'image en orientation 1

de orientation:

  1. ctx.transform(1, 0, 0, 1, 0, 0);
  2. ctx.transform(-1, 0, 0, 1, width, 0);
  3. ctx.transform(-1, 0, 0, -1, width, height);
  4. ctx.transform(1, 0, 0, -1, 0, height);
  5. ctx.transform(0, 1, 1, 0, 0, 0);
  6. ctx.transform(0, 1, -1, 0, height, 0);
  7. ctx.transform(0, -1, -1, 0, height, width);
  8. ctx.transform(0, -1, 1, 0, 0, width);

avant de dessiner l'image sur ctx

34
répondu Mederr 2018-07-25 16:47:21

ok en plus de @user3096626 réponse je pense qu'il sera plus utile si quelqu'un a fourni un exemple de code, l'exemple suivant vous montrera comment corriger l'orientation de l'image vient de l'url (images distantes):


Solution 1: en utilisant javascript (recommandé)

  1. parce que load-image la bibliothèque n'extrait pas les tags exif des images url SEULEMENT (file / blob), nous allons utiliser à la fois exif-js et load-image les bibliothèques javascript, donc d'abord ajouter ces bibliothèques à votre page comme suit:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.1.0/exif.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image-scale.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image-orientation.min.js"></script>
    

    Note la version 2.2 d'exif-js semble avoir des problèmes donc nous avons utilisé 2.1

  2. alors fondamentalement, ce que nous allons faire est

    un - charger l'image en utilisant window.loadImage()

    B - lire les étiquettes exif en utilisant window.EXIF.getData()

    c - convertissez l'image en toile et fixez l'orientation de l'image en utilisant window.loadImage.scale()

    d-placer la toile dans le document

ici, vous allez :)

window.loadImage("/your-image.jpg", function (img) {
  if (img.type === "error") {
    console.log("couldn't load image:", img);
  } else {
    window.EXIF.getData(img, function () {
        var orientation = EXIF.getTag(this, "Orientation");
        var canvas = window.loadImage.scale(img, {orientation: orientation || 0, canvas: true});
        document.getElementById("container").appendChild(canvas); 
        // or using jquery $("#container").append(canvas);

    });
  }
});

bien sûr, vous pouvez aussi obtenir l'image comme base64 de l'objet canvas et le placer dans l'attribut img src, donc, à l'aide de jQuery que vous pouvez faire ;)

$("#my-image").attr("src",canvas.toDataURL());

voici le code complet sur: github: https://github.com/digital-flowers/loadimage-exif-example


Solution 2: en utilisant html (navigateur hack)

il est très rapide et facile hack, la plupart des navigateurs d'afficher l'image dans la bonne orientation si l'image s'ouvre dans un nouvelle onglet directement, sans aucun html (LOL Je ne sais pas pourquoi), donc essentiellement vous pouvez afficher votre image en utilisant iframe en mettant l'attribut iframe src comme l'url de l'image directement:

<iframe src="/my-image.jpg"></iframe>

Solution 3: Utilisation de css (seulement firefox & safari sur ios)

il y a l'attribut css3 pour corriger l'orientation de l'image mais le problème c'est qu'il ne fonctionne que sur firefox et safari/ios il vaut toujours la peine de le mentionner parce que bientôt il sera disponible pour tous les navigateurs (Browser support info from caniuse )

img {
   image-orientation: from-image;
}
19
répondu Fareed Alnamrouti 2017-07-08 16:33:13

la réponse de WunderBart était la meilleure pour moi. Notez que vous pouvez l'accélérer beaucoup si vos images sont souvent le droit chemin, tout simplement en testant l'orientation première et en contournant le reste du code, si pas de rotation est nécessaire.

mettant toutes les infos de wunderbart ensemble, quelque chose comme ça;

var handleTakePhoto = function () {
    let fileInput: HTMLInputElement = <HTMLInputElement>document.getElementById('photoInput');
    fileInput.addEventListener('change', (e: any) => handleInputUpdated(fileInput, e.target.files));
    fileInput.click();
}

var handleInputUpdated = function (fileInput: HTMLInputElement, fileList) {
    let file = null;

    if (fileList.length > 0 && fileList[0].type.match(/^image\//)) {
        isLoading(true);
        file = fileList[0];
        getOrientation(file, function (orientation) {
            if (orientation == 1) {
                imageBinary(URL.createObjectURL(file));
                isLoading(false);
            }
            else 
            {
                resetOrientation(URL.createObjectURL(file), orientation, function (resetBase64Image) {
                    imageBinary(resetBase64Image);
                    isLoading(false);
                });
            }
        });
    }

    fileInput.removeEventListener('change');
}


// from http://stackoverflow.com/a/32490603
export function getOrientation(file, callback) {
    var reader = new FileReader();

    reader.onload = function (event: any) {
        var view = new DataView(event.target.result);

        if (view.getUint16(0, false) != 0xFFD8) return callback(-2);

        var length = view.byteLength,
            offset = 2;

        while (offset < length) {
            var marker = view.getUint16(offset, false);
            offset += 2;

            if (marker == 0xFFE1) {
                if (view.getUint32(offset += 2, false) != 0x45786966) {
                    return callback(-1);
                }
                var little = view.getUint16(offset += 6, false) == 0x4949;
                offset += view.getUint32(offset + 4, little);
                var tags = view.getUint16(offset, little);
                offset += 2;

                for (var i = 0; i < tags; i++)
                    if (view.getUint16(offset + (i * 12), little) == 0x0112)
                        return callback(view.getUint16(offset + (i * 12) + 8, little));
            }
            else if ((marker & 0xFF00) != 0xFF00) break;
            else offset += view.getUint16(offset, false);
        }
        return callback(-1);
    };

    reader.readAsArrayBuffer(file.slice(0, 64 * 1024));
};

export function resetOrientation(srcBase64, srcOrientation, callback) {
    var img = new Image();

    img.onload = function () {
        var width = img.width,
            height = img.height,
            canvas = document.createElement('canvas'),
            ctx = canvas.getContext("2d");

        // set proper canvas dimensions before transform & export
        if (4 < srcOrientation && srcOrientation < 9) {
            canvas.width = height;
            canvas.height = width;
        } else {
            canvas.width = width;
            canvas.height = height;
        }

        // transform context before drawing image
        switch (srcOrientation) {
            case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
            case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
            case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
            case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
            case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
            case 7: ctx.transform(0, -1, -1, 0, height, width); break;
            case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
            default: break;
        }

        // draw image
        ctx.drawImage(img, 0, 0);

        // export base64
        callback(canvas.toDataURL());
    };

    img.src = srcBase64;
}
5
répondu statler 2017-10-30 10:18:18

pour ceux qui ont un fichier à partir d'un contrôle d'entrée, ne savent pas quelle est son orientation, sont un peu paresseux et ne veulent pas inclure une grande bibliothèque ci-dessous est le code fourni par @WunderBart fusionné avec la réponse qu'il renvoie à ( https://stackoverflow.com/a/32490603 ) qui trouve l'orientation.

function getDataUrl(file, callback2) {
        var callback = function (srcOrientation) {
            var reader2 = new FileReader();
            reader2.onload = function (e) {
                var srcBase64 = e.target.result;
                var img = new Image();

                img.onload = function () {
                    var width = img.width,
                        height = img.height,
                        canvas = document.createElement('canvas'),
                        ctx = canvas.getContext("2d");

                    // set proper canvas dimensions before transform & export
                    if (4 < srcOrientation && srcOrientation < 9) {
                        canvas.width = height;
                        canvas.height = width;
                    } else {
                        canvas.width = width;
                        canvas.height = height;
                    }

                    // transform context before drawing image
                    switch (srcOrientation) {
                        case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
                        case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
                        case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
                        case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
                        case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
                        case 7: ctx.transform(0, -1, -1, 0, height, width); break;
                        case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
                        default: break;
                    }

                    // draw image
                    ctx.drawImage(img, 0, 0);

                    // export base64
                    callback2(canvas.toDataURL());
                };

                img.src = srcBase64;
            }

            reader2.readAsDataURL(file);
        }

        var reader = new FileReader();
        reader.onload = function (e) {

            var view = new DataView(e.target.result);
            if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
            var length = view.byteLength, offset = 2;
            while (offset < length) {
                var marker = view.getUint16(offset, false);
                offset += 2;
                if (marker == 0xFFE1) {
                    if (view.getUint32(offset += 2, false) != 0x45786966) return callback(-1);
                    var little = view.getUint16(offset += 6, false) == 0x4949;
                    offset += view.getUint32(offset + 4, little);
                    var tags = view.getUint16(offset, little);
                    offset += 2;
                    for (var i = 0; i < tags; i++)
                        if (view.getUint16(offset + (i * 12), little) == 0x0112)
                            return callback(view.getUint16(offset + (i * 12) + 8, little));
                }
                else if ((marker & 0xFF00) != 0xFF00) break;
                else offset += view.getUint16(offset, false);
            }
            return callback(-1);
        };
        reader.readAsArrayBuffer(file);
    }

qui peut facilement être appelé comme tel

getDataUrl(input.files[0], function (imgBase64) {
      vm.user.BioPhoto = imgBase64;
});
4
répondu runxc1 Bret Ferrier 2017-10-18 16:28:12

j'utilise la solution mixte (php+css).

les conteneurs sont nécessaires pour:

  • div.imgCont2 le conteneur doit tourner;
  • div.imgCont1 container neededed to zoomOut - width:150% ;
  • div.imgCont conteneur nécessaire pour les barres de défilement, lorsque l'image est zoomOut.

.

<?php
    $image_url = 'your image url.jpg';
    $exif = @exif_read_data($image_url,0,true);
    $orientation = @$exif['IFD0']['Orientation'];
?>

<style>
.imgCont{
    width:100%;
    overflow:auto;
}
.imgCont2[data-orientation="8"]{
    transform:rotate(270deg);
    margin:15% 0;
}
.imgCont2[data-orientation="6"]{
    transform:rotate(90deg);
    margin:15% 0;
}
.imgCont2[data-orientation="3"]{
    transform:rotate(180deg);
}
img{
    width:100%;
}
</style>

<div class="imgCont">
  <div class="imgCont1">
    <div class="imgCont2" data-orientation="<?php echo($orientation) ?>">
      <img src="<?php echo($image_url) ?>">
    </div>
  </div>
</div>
1
répondu Sergey S 2017-09-02 11:28:47

en plus de la réponse de @fareed namrouti,

ceci doit être utilisé si l'image doit être parcourue à partir d'un élément d'entrée de fichier

<input type="file" name="file" id="file-input"><br/>
image after transform: <br/>
<div id="container"></div>

<script>
    document.getElementById('file-input').onchange = function (e) {
        var image = e.target.files[0];
        window.loadImage(image, function (img) {
            if (img.type === "error") {
                console.log("couldn't load image:", img);
            } else {
                window.EXIF.getData(image, function () {
                    console.log("load image done!");
                    var orientation = window.EXIF.getTag(this, "Orientation");
                    var canvas = window.loadImage.scale(img,
                        {orientation: orientation || 0, canvas: true, maxWidth: 200});
                    document.getElementById("container").appendChild(canvas);
                    // or using jquery $("#container").append(canvas);
                });
            }
        });
    };
</script>
0
répondu Perry 2017-07-08 19:04:51

j'ai écrit un petit script php qui fait tourner l'image. Assurez-vous de stocker l'image en faveur de recalculer chaque requête.

<?php

header("Content-type: image/jpeg");
$img = 'IMG URL';

$exif = @exif_read_data($img,0,true);
$orientation = @$exif['IFD0']['Orientation'];
if($orientation == 7 || $orientation == 8) {
    $degrees = 90;
} elseif($orientation == 5 || $orientation == 6) {
    $degrees = 270;
} elseif($orientation == 3 || $orientation == 4) {
    $degrees = 180;
} else {
    $degrees = 0;
}
$rotate = imagerotate(imagecreatefromjpeg($img), $degrees, 0);
imagejpeg($rotate);
imagedestroy($rotate);

?>

Cheers

0
répondu Thom 2018-03-18 16:12:07