Les photos d'appareils photo numériques sont souvent enregistrées au format JPEG avec une balise EXIF "d'orientation". Pour que l'affichage soit correct, les images doivent être pivotées/inversées en fonction de l'orientation définie, mais les navigateurs ignorent ces informations lors du rendu de 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 bon résumé des 8 orientations différentes qu'un JPEG peut avoir:
Des exemples d'images sont disponibles à l'adresse 4 .
La question est de savoir comment faire pivoter/refléter l'image côté client afin qu'elle s'affiche correctement et puisse être traitée ultérieurement si nécessaire.
Des bibliothèques JS sont disponibles pour analyser les données EXIF, notamment l'attribut d'orientation 2 . Flickr a noté un problème de performance possible lors de l'analyse d'images volumineuses, nécessitant l'utilisation de travailleurs Web 3 .
Les outils de la console peuvent correctement réorienter les images 5 . Un script PHP permettant de résoudre le problème est disponible à l'adresse 6
Le projet github JavaScript-Load-Image fournit une solution complète au problème d’orientation EXIF, en effectuant correctement la rotation/symétrie des images pour les 8 orientations exif. Voir la démo en ligne de javascript exif orientation
L'image est dessinée sur une toile HTML5. Son rendu correct est implémenté dans js/load-image-orientation.js via des opérations de canevas.
J'espère que cela fera gagner un peu de temps à quelqu'un d'autre et qu'il renseignera les moteurs de recherche sur ce bijou open source :)
La transformation du contexte de Mederr fonctionne parfaitement. Si vous avez besoin d'extraire l'orientation uniquement, utilisez this function - vous n'avez pas besoin de bibliothèques à lecture EXIF. Vous trouverez ci-dessous une fonction permettant de redéfinir l’orientation dans une image base64 . Voici un violon pour elle . J'ai également préparé un violon avec une démonstration 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;
};
ok en plus de @ user3096626 answer, 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 à partir de l'URL (images distantes):
Solution 1: utilisation de javascript (recommandé)
comme la bibliothèque load-image ne permet pas d'extraire les tags exif à partir d'images url (fichier/blob), nous utiliserons à la fois exif-js et load-image bibliothèques javascript, ajoutez d’abord 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, nous avons donc utilisé la version 2.1
alors fondamentalement ce que nous ferons est
a - chargez l'image en utilisant window.loadImage()
b - lit les tags exif en utilisant window.EXIF.getData()
c - convertissez l'image en canevas et corrigez l'orientation de l'image à l'aide de window.loadImage.scale()
d - place la toile dans le document
voici :)
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 en base64 à partir de l'objet canvas et la placer dans l'attribut img src, vous pouvez donc utiliser jQuery;)
$("#my-image").attr("src",canvas.toDataURL());
voici le code complet sur: github: https://github.com/digital-flowers/loadimage-exif-example
Solution 2: utilisation de HTML (piratage du navigateur)
il y a un hack très rapide et facile, la plupart des navigateurs affichent l'image dans l'orientation correcte si l'image est ouverte dans un nouvel onglet directement sans html (LOL, je ne sais pas pourquoi), vous pouvez donc afficher votre image en utilisant iframe en mettant l'attribut iframe src directement dans l'URL de l'image:
<iframe src="/my-image.jpg"></iframe>
Solution 3: utilisation de css (seulement firefox et safari sur ios)
il y a un 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, cela vaut encore la peine d'être mentionné car bientôt il sera disponible pour tous les navigateurs (Informations de support du navigateur de caniuse)
img {
image-orientation: from-image;
}
La réponse de WunderBart était la meilleure pour moi. Notez que vous pouvez accélérer beaucoup si vos images sont souvent le bon sens, simplement en testant d'abord l'orientation et en contournant le reste du code si aucune rotation n'est requise.
Rassembler toutes les informations de wunderbart, quelque chose comme ceci;
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;
}
Pour ceux qui ont un fichier d'un contrôle d'entrée, ne savent pas quelle est son orientation, sont un peu fainéants et ne veulent pas inclure une grande bibliothèque. Le code fourni par @WunderBart est associé à la réponse à laquelle 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 s'appeler comme tel
getDataUrl(input.files[0], function (imgBase64) {
vm.user.BioPhoto = imgBase64;
});
En plus de la réponse de @fareed namrouti,
Ceci devrait être utilisé si l'image doit être parcourue à partir d'un élément input 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>
J'utilise une solution mixte (php + css).
Les conteneurs sont nécessaires pour:
div.imgCont2
conteneur nécessaire pour la rotation;div.imgCont1
conteneur nécessaire pour 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>
J'ai écrit un petit script php qui fait pivoter l'image. Assurez-vous de stocker l'image au lieu de la recalculer à chaque demande.
<?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);
?>
À votre santé