web-dev-qa-db-fra.com

Compression d'images uri de données base64

Problème

Je crée plusieurs graphiques qui sont ensuite envoyés au serveur pour créer un PDF. Ces données peuvent devenir volumineuses.

Question

Quelle est la meilleure façon de compresser et d'envoyer les données d'image au serveur

Contexte

Les graphiques que je crée sont assez complexes, pour éviter le mal de tête, tout cela est converti en un canevas où l'uri de données base64 est généré. Actuellement, les uri (s) de données sont publiées sur le serveur pour gérer le traitement. Les informations publiées peuvent devenir assez volumineuses à environ 400-600 Ko chacune pour un petit graphique et 12 Mo pour le plus grand graphique.

Les graphiques sont des organigrammes qui peuvent être manipulés/réorganisés.

Existe-t-il une meilleure méthode de compression de ces chaînes avant de les renvoyer au serveur?

Recherche

Certaines choses que j'ai vérifiées:

https://github.com/brunobar79/J-I-C/blob/master/src/JIC.js (ne ressemble pas à une option juste redimensionne)

http://Pastebin.com/MhJZBsqW (semble intéressant)

Mais fait référence à des bibliothèques externes que je ne trouve pas: C_H_ImageLib_MinifyJpeg

https://code.google.com/p/jslzjb/source/browse/trunk/Iuppiter.js?r=2 (on dirait que cela pourrait fonctionner mais repose sur la décompression côté serveur)

22
David Nguyen

La compression des chaînes est peut-être la solution pour vous. Cela convertit les données en tableaux d'octets.

Il existe plusieurs implémentations et algorithmes, par exemple

  • LZMA-JS Une implémentation JavaScript autonome de l'algorithme de compression de la chaîne Lempel-Ziv-Markov (LZMA).

    my_lzma = new LZMA("./lzma_worker.js");
    my_lzma.compress("This is my compression test.", 1, function on_compress_complete(result) {
        console.log("Compressed: " + result);
        my_lzma.decompress(result, function on_decompress_complete(result) {
            console.log("Decompressed: " + result);
        }, function on_decompress_progress_update(percent) {
            console.log("Decompressing: " + (percent * 100) + "%");
        });
    }, function on_compress_progress_update(percent) {
        console.log("Compressing: " + (percent * 100) + "%");
    });
    
  • lz-string : Compression JavaScript, rapide!

    var str = "This is my compression test.";
    console.log("Size of sample is: " + str.length);
    var compressed = LZString.compress(str);
    console.log("Size of compressed sample is: " + compressed.length);
    str = LZString.decompress(compressed);
    console.log("Sample is: " + str);
    
37
Koen.

J'avais besoin de générer des miniatures à partir d'images plus grandes. J'ai décidé de résoudre ma version de ce problème avec la technique HTML5 Canvas. J'utilise GWT donc mon code est:

//Scale to size
public static String scaleImage(Image image, int width, int height) {

    Canvas canvasTmp = Canvas.createIfSupported();
    Context2d context = canvasTmp.getContext2d();

    canvasTmp.setCoordinateSpaceWidth(width);
    canvasTmp.setCoordinateSpaceHeight(height);

    ImageElement imageElement = ImageElement.as(image.getElement());

    context.drawImage(imageElement, 0, 0, width, height);

    //Most browsers support an extra option for: toDataURL(mime type, quality) where quality = 0-1 double.
    //This is not available through this Java library but might work with elemental version?
    String tempStr = canvasTmp.toDataUrl("image/jpeg");

    return tempStr;
}

Si vous utilisez JS, vous pouvez probablement avoir l'idée:

  • Faire un canevas de la taille de l'image de sortie souhaitée
  • dessine l'image d'entrée sur la toile dans la nouvelle taille
  • appel canvas.toDataURL ("type mime", qualité)

Vous pouvez utiliser n'importe quel type MIME, je pense, mais pour moi, le format JPEG était le plus petit et était comparable aux résultats de mon programme d'image de bureau.

Mon GWT ne me permettait pas de faire le paramètre de qualité (et je ne suis pas sûr à 100% de la façon dont il est largement pris en charge dans les navigateurs), mais c'était OK car les images résultantes étaient assez petites. Si vous laissez le type MIME vierge, il s'agit par défaut de png qui dans mon cas était 3-4x plus grand que jpeg.

8
Jesse Adamson

J'ai finalement réussi à travailler avec des fichiers assez volumineux.

Pour ce faire, j'ai utilisé lz-string, comme indiqué ci-dessus.

Il y a un problème cependant, c'est que l'envoi de données UTF-16 via ajax est obsolète , donc .. cela ne fonctionne pas. Le correctif consiste à convertir vers et depuis UTF-16 et UTF-8.

Voici le code de conversion que j'utilise. Je ne sais pas quel est l'endian standard, btw:

var UTF = {};

UTF.U16to8 = function(convertMe) {
var out = "";
  for(var i = 0; i < convertMe.length; i++) {
      var charCode = convertMe.charCodeAt(i);
      out += String.fromCharCode(~~(charCode/256));
      out += String.fromCharCode(charCode%256);
    }
  return out;
}

UTF.U8to16 = function(convertMe) {
  var out = ""
  for(var i = 0; i < convertMe.length; i += 2) {
    var charCode = convertMe.charCodeAt(i)*256;
    charCode += convertMe.charCodeAt(i+1);
    out += String.fromCharCode(charCode)
  }
  return out;
}

Si vous utilisez Node.js, ce code fonctionne des deux côtés. Sinon, vous devrez écrire votre propre version de ces convertisseurs côté serveur.

Phew! Quelle journée c'était.

3
Seph Reed

Ce n'est pas vraiment une réponse satisfaisante, mais il n'y a probablement pas de bibliothèques qui donnent le résultat souhaité.

Vous dites que le redimensionnement n'est pas une option, mais alors, qu'est-ce que c'est? Seulement une compression sans perte? Les chaînes Base64 représentent déjà une image compressée, je ne pense pas qu'aucune bibliothèque fournira une compression sans perte.

0
T.S.