Projet

Général

Profil

Development #23152

Champ de type fichier : option pour redimensionner les fichiers image

Ajouté par Frédéric Péters il y a environ 6 ans. Mis à jour il y a presque 5 ans.

Statut:
Fermé
Priorité:
Normal
Assigné à:
Version cible:
-
Début:
13 avril 2018
Echéance:
% réalisé:

0%

Temps estimé:
Patch proposed:
Oui
Planning:
Non

Description

Soit côté client pour déjà économiser de la bande passante (un vieil article sur le sujet https://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/), soit côté serveur, pour limiter les besoins en stockage.


Fichiers

Révisions associées

Révision 551bb349 (diff)
Ajouté par Frédéric Péters il y a presque 5 ans

misc: add option to resize images before upload (#23152)

Historique

#1

Mis à jour par Frédéric Péters il y a environ 6 ans

Ticket après avoir noté des fichiers tiff de >30 Mo (gm identify → TIFF 3024x4032+0+0 DirectClass 8-bit 34.9Mi 0.000u 0m:0.000003s)

Mais aussi des jpg, et là faut aller encore plus haut (JPEG 11811x7087+0+0 DirectClass 8-bit 44.1Mi 0.000u 0m:0.000002s).

#2

Mis à jour par Frédéric Péters il y a environ 6 ans

  • Priorité changé de Normal à Bas
#7

Mis à jour par Frédéric Péters il y a environ 5 ans

  • Statut changé de Nouveau à En cours
  • Assigné à mis à Frédéric Péters
#8

Mis à jour par Frédéric Péters il y a presque 5 ans

Malheureusement c'est surtout du js où on n'a pas d'infra pour tester.

Dans le patch j'active par défaut le redimensionnement (avec une option pour le désactiver), si on considère risqué de balancer ça partout, je peux l'inverser.

#9

Mis à jour par Frédéric Péters il y a presque 5 ans

Pas de risque, off par défaut.

#10

Mis à jour par Nicolas Roche il y a presque 5 ans

Juste pour être sûr de bien comprendre :

  • Cf le lien donné dans l'entête du ticket :

ctx.drawImage(img, 0, 0, width, height) et canvas.toDataURL pour diminuer les dimensions de l'image (et la résolution).

ExifRestorer.restore_as_blob pour à la fois :
- garder les métadonnées EXIF
- améliorer la qualité de l'image tronquée (interpolation linéaire)

J'ai l'impression que le code d'ExifRestorer plante (silencieusement) sur les grosses images : chez moi à partir de 6.2 Mo (j'essaye d'affiner asap).

#11

Mis à jour par Nicolas Roche il y a presque 5 ans

Arf, je me suis trompé.
Pas de problème avec les JPEG (testé jusqu'à 8.7 Mo)
Par contre c'est avec les PNG que ça plante, quelque soit la taille.

#12

Mis à jour par Frédéric Péters il y a presque 5 ans

  • Statut changé de Solution proposée à En cours

Par contre c'est avec les PNG que ça plante, quelque soit la taille.

Ok et en fait cette partie "exif" est pas trop nécessaire sur les PNG, je vais la faire sauter.

#13

Mis à jour par Frédéric Péters il y a presque 5 ans

Ce qui n'était pas nécessaire non plus c'était redimensionner les petits fichiers; ce patch corrige ça, interdiff :

@@ -232,25 +232,38 @@ $.WcsFileUpload = {
                             var width = img.width;
                             var height = img.height;

-                            if (width > height) {
-                                if (width > MAX_WIDTH) {
-                                    height *= MAX_WIDTH / width;
-                                    width = MAX_WIDTH;
-                                }
-                            } else {
-                                if (height > MAX_HEIGHT) {
-                                    width *= MAX_HEIGHT / height;
-                                    height = MAX_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 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';
                                 }
+                                data.files[0] = blob;
                             }
-                            canvas.width = width;
-                            canvas.height = height;
-                            var ctx = canvas.getContext('2d');
-                            ctx.drawImage(img, 0, 0, width, height);
-                            var new_image_64 = canvas.toDataURL('image/jpeg', 0.95);
-                            var blob = ExifRestorer.restore_as_blob(original_image_64, new_image_64);
-                            blob.name = data.files[0].name;
-                            data.files[0] = blob;
                             return $.WcsFileUpload.upload(base_widget, data);
                         }
                         img.src = e.target.result;
#14

Mis à jour par Nicolas Roche il y a presque 5 ans

  • Statut changé de Solution proposée à Solution validée

Je valide :

Marche bien sur les plus gros fichiers que j'ai réussi à fabriquer :
  • JPEG:
    • 26Mo : 4 secondes
  • PNG:
    • 192 Mo : 2 secondes

Dans les 2 cas, les images sont réduites à 2.4 Mo

Pour comparaison, avec TIFF (avec qui le patch ne s'applique pas) :
  • TIFF:
    • 24 Mo ok
    • 75 Mo (Erreur lors du transfert en rouge dans la barre de progression)

Pour information seulement, c'est assez aléatoire mais je remarque :
- rien d'affiché pour JPEG
- parfois 'rezising image' affiché dans la barre pour PNG
Vu le code,
$(base_widget).find('.fileprogress .bar').css('width', '100%');
je m'attendais à voir une barre de progression.

ça pourrait peut-être être amélioré par la suite car le fait de cliquer sur suivant, avant que l'affichage n'indique que l'image soit téléchargée, fait échouer l'upload (aussi bien pour PNG que JPEG). cependant avec des JPEG de 8 Mo, on a à peine le temps de cliquer (c'est immédiat pour les PNG de 8 Mo).

#15

Mis à jour par Frédéric Péters il y a presque 5 ans

  • Statut changé de Solution validée à Résolu (à déployer)

75 Mo (Erreur lors du transfert en rouge dans la barre de progression)

Je miserais sur une erreur au niveau de nginx (client_max_body_size).

Vu le code,
$(base_widget).find('.fileprogress .bar').css('width', '100%');
je m'attendais à voir une barre de progression.

Il y a une barre de progression le temps de l'upload et elle est réutilisée mise à 100% ici parce qu'usuellement le texte qui y apparait est plus lisible sur le fond de couleur de la barre que sur le fond blanc. (c'est pour le texte "resizing").

le fait de cliquer sur suivant, avant que l'affichage n'indique que l'image soit téléchargée, fait échouer l'upload

Curieux normalement ça devrait être désactivé pendant l'upload (#9882). (bug trouvé, #33053)

on a à peine le temps de cliquer

Côté mesures, faut aussi imaginer que ça va être utilisé par des téléphones, moins puissants et sur des réseaux moins rapides. (il y a dans chromium de quoi simuler la partie réseau).

commit 551bb349e05c7e7bb2c8265437fc10a1d9773270
Author: Frédéric Péters <fpeters@entrouvert.com>
Date:   Sun Mar 3 18:00:30 2019 +0100

    misc: add option to resize images before upload (#23152)
#16

Mis à jour par Frédéric Péters il y a presque 5 ans

  • Statut changé de Résolu (à déployer) à Solution déployée

Formats disponibles : Atom PDF