Maison > interface Web > Tutoriel H5 > Le terminal mobile utilise H5 pour mettre en œuvre la fonction de compression des téléchargements d'images

Le terminal mobile utilise H5 pour mettre en œuvre la fonction de compression des téléchargements d'images

不言
Libérer: 2018-06-11 16:41:34
original
2565 Les gens l'ont consulté

Cet article présente principalement en détail l'utilisation de H5 pour réaliser la fonction de téléchargement d'images compressées sur le terminal mobile. Il a une certaine valeur de référence. Les amis intéressés peuvent s'y référer

Un collègue m'a déjà parlé. . Concernant la fonction d'utiliser Canvas pour compresser des images sur le terminal mobile puis les télécharger, j'ai récemment eu du temps libre, alors je l'ai mis en pratique. Le lien de l’effet démo est publié au bas de l’article.

Lors du téléchargement de photos sur le terminal mobile, les utilisateurs téléchargent des photos locales sur le téléphone mobile, et les photos locales sont généralement relativement volumineuses. Prenez l'iPhone6 ​​​​​​comme exemple. De nombreuses photos prises ont généralement une taille d'un ou deux mégaoctets. . Si vous la téléchargez directement comme ceci, l'image sera trop grande. Si l'utilisateur utilise des données mobiles, télécharger l'image complètement n'est évidemment pas une bonne idée.

Actuellement, diverses nouvelles API HTML5 ont été mieux implémentées sur le webkit mobile. Selon caniuse, les objets FileReader, Blob et Formdata utilisés dans cette démo ont été implémentés dans la plupart des navigateurs d'appareils mobiles (safari6.0+, android 3.0+), donc la compression des images directement sur le front-end est devenue une solution essentielle. fonctions de téléchargement d'images sur des appareils mobiles.

La compression et le téléchargement d'images sur le terminal mobile utilisent principalement les trois API h5 de filereader, canvas et formdata. La logique n'est pas difficile. L'ensemble du processus est le suivant :

(1) Lorsque l'utilisateur utilise le fichier d'entrée pour télécharger une image, utilisez filereader pour lire les données d'image téléchargées par l'utilisateur (format base64)

(2) Passer les données de l'image dans l'objet img, puis dessinez img sur canevas, puis appelez canvas.toDataURL pour compresser l'image

(3) Obtenez les données d'image compressées au format base64, convertissez-les en binaire et insérez-les dans formdata, puis soumettez les données du formulaire via XmlHttpRequest .

Dans ces trois étapes, la compression et le téléchargement de l'image sont terminés.

Cela semble simple, mais en réalité, il existe encore quelques pièges. Ensuite, analysez-le directement avec le code :

[1] Obtenez les données d'image

Tout d'abord, récupérez les données d'image, c'est-à-dire écoutez l'événement de changement de l'entrée fichier, puis obtenez Pour les fichiers d'objet de fichier téléchargés, convertissez les fichiers de type tableau en un tableau, puis effectuez une traversée forEach.

Déterminez ensuite le type de fichier. S'il ne s'agit pas d'une image, elle ne sera pas traitée. S'il s'agit d'une image, instanciez un lecteur de fichiers, lisez les données du fichier téléchargé au format base64 et déterminez la longueur des données. Si l'image est supérieure à 200 Ko, appelez la méthode compress pour la compresser, sinon appelez la méthode upload pour la télécharger.

filechooser.onchange = function () {
   if (!this.files.length) return;
 
   var files = Array.prototype.slice.call(this.files);
 
   if (files.length > 9) {
    alert("最多同时只可上传9张图片");
    return;
   }
 
   files.forEach(function (file, i) {
    if (!/\/(?:jpegpnggif)/i.test(file.type)) return;
 
    var reader = new FileReader();
 
    var li = document.createElement("li");
    li.innerHTML = "<p class="progress"><span></span></p>";
    $(".img-list").append($(li));
 
    reader.onload = function () {
     var result = this.result;
     var img = new Image();
     img.src = result;
 
     //如果图片大小小于200kb,则直接上传
     if (result.length <= maxsize) {
      $(li).css("background-image", "url(" + result + ")");
      img = null;
      upload(result, file.type, $(li));
 
      return;
     }
 
 //    图片加载完毕之后进行压缩,然后上传
     if (img.complete) {
      callback();
     } else {
      img.onload = callback;
     }
 
     function callback() {
      var data = compress(img);
 
      $(li).css("background-image", "url(" + data + ")");
 
      upload(data, file.type, $(li));
 
      img = null;
     }
 
    };
 
    reader.readAsDataURL(file);
   })
  };
Copier après la connexion

【2】Compresser les images

Après avoir obtenu les données d'image ci-dessus, vous pouvez utiliser la méthode de compression pour compresser les images. La compression d'images n'implique pas de dessiner directement l'image sur le canevas, puis d'appeler toDataURL.

Dans IOS, il existe deux limitations pour dessiner des images sur toile :

La première est la taille de l'image. Si la taille de l'image dépasse deux millions de pixels, l'image ne peut pas être dessinée. sur le canevas, aucune erreur ne sera signalée lors de l'appel de drawImage, mais lorsque vous utilisez toDataURL pour obtenir des données d'image, vous obtiendrez des données d'image vides.

De plus, la taille de la toile est limitée. Si la taille de la toile est supérieure à environ cinq millions de pixels (c'est-à-dire le produit de la largeur et de la hauteur), non seulement l'image ne peut pas être dessinée, mais aussi d'autres. les choses ne peuvent pas être dessinées.

Pour faire face à la première limitation, la solution est de dessiner des tuiles. Le dessin de tuiles consiste à diviser l'image en plusieurs morceaux et à les dessiner sur la toile. La méthode dans mon code consiste à diviser l'image en 1 million de pixels, puis à la dessiner sur la toile.

Pour faire face à la deuxième limitation, ma solution consiste à compresser de manière appropriée la largeur et la hauteur de l'image. Pour des raisons de sécurité, la limite supérieure dans mon code est de quatre millions de pixels si l'image est plus grande que. quatre millions de pixels, compressez-le simplement à moins de 4 millions de pixels. Une image de 4 mégapixels devrait suffire, avec une largeur et une hauteur de 2000X2000.

De cette façon, les deux limitations sur IOS sont résolues.

En plus des limitations mentionnées ci-dessus, il existe deux pièges. Le premier est que le toDataURL de Canvas ne peut compresser que le format jpg. Lorsque l'image téléchargée par l'utilisateur est au format png, elle doit être convertie en jpg, c'est-à-dire. Autrement dit, il peut être utilisé uniformément. canvas.toDataURL("image/jpeg", 0.1), le type est uniformément défini sur jpeg et le taux de compression est contrôlé par lui-même.

L'autre est que si vous convertissez png en jpg et que vous le dessinez sur la toile, si la toile a une zone transparente, la zone transparente deviendra noire lorsque vous la convertirez en jpg, car les pixels transparents de la toile sont par défaut en rgba( 0,0,0,0), donc une fois converti en jpg, il devient rgba(0,0,0,1), c'est-à-dire que l'arrière-plan transparent deviendra noir. La solution est de poser un fond blanc sur la toile avant de dessiner.

function compress(img) {
  var initSize = img.src.length;
  var width = img.width;
  var height = img.height;

  //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
  var ratio;
  if ((ratio = width * height / 4000000)>1) {
   ratio = Math.sqrt(ratio);
   width /= ratio;
   height /= ratio;
  }else {
   ratio = 1;
  }

  canvas.width = width;
  canvas.height = height;

//  铺底色
  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  //如果图片像素大于100万则使用瓦片绘制
  var count;
  if ((count = width * height / 1000000) > 1) {
   count = ~~(Math.sqrt(count)+1); //计算要分成多少块瓦片

//   计算每块瓦片的宽和高
   var nw = ~~(width / count);
   var nh = ~~(height / count);

   tCanvas.width = nw;
   tCanvas.height = nh;

   for (var i = 0; i < count; i++) {
    for (var j = 0; j < count; j++) {
     tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);

     ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
    }
   }
  } else {
   ctx.drawImage(img, 0, 0, width, height);
  }

  //进行最小压缩
  var ndata = canvas.toDataURL("image/jpeg", 0.1);

  console.log("压缩前:" + initSize);
  console.log("压缩后:" + ndata.length);
  console.log("压缩率:" + ~~(100 * (initSize - ndata.length) / initSize) + "%");

  tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;

  return ndata;
 }
Copier après la connexion

[3] Téléchargement d'image

Une fois l'image compressée, elle peut être insérée dans formdata . Téléchargé, convertissez d'abord les données base64 en chaîne, puis instanciez un ArrayBuffer, puis transmettez la chaîne dans l'ArrayBuffer au format d'un entier de 8 bits, puis utilisez l'objet BlobBuilder ou Blob pour convertir l'ArrayBuffer entier de 8 bits. dans un objet blob binaire, puis ajoutez l'objet blob à formdata, puis envoyez-le en arrière-plan via ajax.

XmlHttpRequest2 peut non seulement envoyer du Big Data, mais dispose également d'API supplémentaires telles que l'obtention de la progression de l'envoi, que j'ai également implémentées de manière simple dans mon code.

// 图片上传,将base64的图片转成二进制对象,塞进formdata上传
 function upload(basestr, type, $li) {
  var text = window.atob(basestr.split(",")[1]);
  var buffer = new ArrayBuffer(text.length);
  var ubuffer = new Uint8Array(buffer);
  var pecent = 0 , loop = null;

  for (var i = 0; i < text.length; i++) {
   ubuffer[i] = text.charCodeAt(i);
  }

  var Builder = window.WebKitBlobBuilder window.MozBlobBuilder;
  var blob;

  if (Builder) {
   var builder = new Builder();
   builder.append(buffer);
   blob = builder.getBlob(type);
  } else {
   blob = new window.Blob([buffer], {type: type});
  }

  var xhr = new XMLHttpRequest();
  var formdata = new FormData();
  formdata.append("imagefile", blob);

  xhr.open("post", "/cupload");

  xhr.onreadystatechange = function () {
   if (xhr.readyState == 4 && xhr.status == 200) {
    console.log("上传成功:" + xhr.responseText);

    clearInterval(loop);

    //当收到该消息时上传完毕
    $li.find(".progress span").animate({"width": "100%"}, pecent < 95 ? 200 : 0, function () {
     $(this).html("上传成功");
    });

    $(".pic-list").append("<a href="" + xhr.responseText + " rel="external nofollow" ">" + xhr.responseText + "<img src="" + xhr.responseText + "" /></a>")
   }
  };

  //数据发送进度,前50%展示该进度
  xhr.upload.addEventListener("progress", function (e) {
   if (loop) return;

   pecent = ~~(100 * e.loaded / e.total) / 2;
   $li.find(".progress span").css("width", pecent + "%");

   if (pecent == 50) {
    mockProgress();
   }
  }, false);

  //数据后50%用模拟进度
  function mockProgress() {
   if (loop) return;

   loop = setInterval(function () {
    pecent++;
    $li.find(".progress span").css("width", pecent + "%");

    if (pecent == 99) {
     clearInterval(loop);
    }
   }, 100)
  }

  xhr.send(formdata);
 }
Copier après la connexion

     至此,整个上传的前端图片压缩就完成了,因为是用了formdata提交,所以后台接数据的时候就跟普通form表单提交数据一样处理即可。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

关于H5调用相机拍照并压缩图片的代码

关于H5新属性audio音频和video视频的控制解析

Angular下H5多张上传图片的方法

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal