Utiliser exif.js pour inverser l'orientation appliquée par canva.drawImage() (#73872) #154

Merged
bdauvergne merged 1 commits from wip/73872-Reorientation-d-une-image-suite into main 2023-03-17 00:07:33 +01:00
3 changed files with 1165 additions and 40 deletions

View File

@ -87,6 +87,7 @@ class HTTPResponse(quixote.http_response.HTTPResponse):
'jquery.js',
'jquery-ui.js',
'jquery.iframe-transport.js',
'exif.js',
'jquery.fileupload.js',
]
)

1064
wcs/qommon/static/js/exif.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -255,49 +255,109 @@ $.WcsFileUpload = {
var original_image_64 = e.target.result;
var img = document.createElement("img");
img.onload = function() {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 2000;
var MAX_HEIGHT = 2000;
var width = img.width;
var height = img.height;
if (width > height && width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
} else if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
if (img.width != width || img.height != height) {
canvas.width = width;
canvas.height = height;
var adapt_image = function(orientation) {
/*
* 1 = Horizontal (normal)
* 2 = Mirror horizontal
* 3 = Rotate 180
* 4 = Mirror vertical
* 5 = Mirror horizontal and rotate 270 CW
* 6 = Rotate 90 CW
* 7 = Mirror horizontal and rotate 90 CW
* 8 = Rotate 270 CW */
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height);
var new_image_64 = canvas.toDataURL('image/jpeg', 0.95);
var blob = null;
if (data.files[0].type == 'image/jpeg') {
blob = ExifRestorer.restore_as_blob(original_image_64, new_image_64);
blob.name = data.files[0].name;
} else {
// adapted from dataURItoBlob, from
// https://stackoverflow.com/questions/12168909/blob-from-dataurl#12300351
var byteString = atob(new_image_64.split(',')[1]);
var mimeString = new_image_64.split(',')[0].split(':')[1].split(';')[0]
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
blob = new Blob([ab], {type: mimeString});
blob.name = data.files[0].name + '.jpg';
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 2000;
var MAX_HEIGHT = 2000;
var width = img.width;
var height = img.height;
if (width > height && width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
} else if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
data.files[0] = blob;
if (img.width != width || img.height != height) {
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
switch (orientation) {
case 1:
break;
case 2:
ctx.translate(width, 0);
ctx.scale(-1, 1);
break;
case 3:
ctx.translate(width, height);
ctx.rotate(180 / 180 * Math.PI);
break;
case 4:
ctx.translate(0, height);
ctx.scale(1, -1);
break;
case 5:
canvas.width = height;
canvas.height = width;
ctx.rotate(90 / 180 * Math.PI);
ctx.scale(1, -1);
break;
case 6:
canvas.width = height;
canvas.height = width;
ctx.rotate(-90 / 180 * Math.PI);
ctx.translate(-width, 0);
break;
case 7:
canvas.width = height;
canvas.height = width;
ctx.rotate(270 / 180 * Math.PI);
ctx.translate(-width, height);
ctx.scale(1, -1);
break;
case 8:
canvas.width = height;
canvas.height = width;
ctx.translate(height, 0);
ctx.rotate(-270 / 180 * Math.PI);
break;
}
ctx.drawImage(img, 0, 0, width, height);
var new_image_64 = canvas.toDataURL('image/jpeg', 0.95);
var blob = null;
if (data.files[0].type == 'image/jpeg') {
blob = ExifRestorer.restore_as_blob(original_image_64, new_image_64);
Review

Ça vaudrait peut-être le coup de faire ce test avant de transformer l'image : le standard PNG a intégré les métadonnées Exif depuis 2017, bien que ça ne semble pas supporté par mon navigateur (https://zpl.fi/exif-orientation-in-different-formats/) et que donc je doute très fort qu'exif.js le supporte. Je n'ai pas pu le vérifier : quand je télécharge une image PNG elle est convertie en JPEG quelque part que j'ai pas trouvé avant d'exécuter ce code. Si la conversion PNG => JPG est voulue et systématique en amont, on pourrait carrément dégager le test.

Ça vaudrait peut-être le coup de faire ce test avant de transformer l'image : le standard PNG a intégré les métadonnées Exif depuis 2017, bien que ça ne semble pas supporté par mon navigateur (https://zpl.fi/exif-orientation-in-different-formats/) et que donc je doute très fort qu'exif.js le supporte. Je n'ai pas pu le vérifier : quand je télécharge une image PNG elle est convertie en JPEG quelque part que j'ai pas trouvé avant d'exécuter ce code. Si la conversion PNG => JPG est voulue et systématique en amont, on pourrait carrément dégager le test.
Review

Non t'as raison j'ai complètement changer la logique du truc niveau filtrage des images jpeg, je vais reprendre ça.

Non t'as raison j'ai complètement changer la logique du truc niveau filtrage des images jpeg, je vais reprendre ça.
Review

Voilà j'ai sorti le gros de la fonction dans adapt_image et EXIF.getData n'est plus appelé que sur des images supposément jpeg.

Voilà j'ai sorti le gros de la fonction dans adapt_image et EXIF.getData n'est plus appelé que sur des images supposément jpeg.
blob.name = data.files[0].name;
} else {
// adapted from dataURItoBlob, from
// https://stackoverflow.com/questions/12168909/blob-from-dataurl#12300351
var byteString = atob(new_image_64.split(',')[1]);
var mimeString = new_image_64.split(',')[0].split(':')[1].split(';')[0]
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
blob = new Blob([ab], {type: mimeString});
blob.name = data.files[0].name + '.jpg';
}
data.files[0] = blob;
}
$(base_widget).find('.file-button').trigger('wcs:image-blob', data.files[0]);
return $.WcsFileUpload.upload(base_widget, data);
};
if (data.files[0].type == 'image/jpeg') {
EXIF.getData(img, function () {
var orientation = +EXIF.getTag(this, "Orientation");
adapt_image(orientation);
});
} else {
adapt_image(0);
}
$(base_widget).find('.file-button').trigger('wcs:image-blob', data.files[0]);
return $.WcsFileUpload.upload(base_widget, data);
}
img.src = e.target.result;
}