Heim > Web-Frontend > H5-Tutorial > Hauptteil

Das mobile Endgerät verwendet H5, um die Funktion zum Komprimieren von Bild-Uploads zu implementieren

不言
Freigeben: 2018-06-11 16:41:34
Original
2468 Leute haben es durchsucht

Dieser Artikel stellt hauptsächlich die Verwendung von H5 zur Realisierung der Funktion zum Hochladen komprimierter Bilder auf dem mobilen Endgerät vor. Er hat einen gewissen Referenzwert.

Ein Kollege hat bereits mit mir gesprochen In Bezug auf die Funktion, Bilder auf dem mobilen Endgerät mit Canvas zu komprimieren und dann hochzuladen, hatte ich kürzlich etwas Freizeit und habe sie in die Praxis umgesetzt. Der Link zum Demoeffekt befindet sich am Ende des Artikels.

Beim Hochladen von Bildern auf das mobile Endgerät laden Benutzer lokale Bilder auf das Mobiltelefon hoch, und lokale Bilder sind im Allgemeinen relativ groß. Nehmen wir zum Beispiel das iPhone6. Viele aufgenommene Bilder haben normalerweise eine Größe von ein oder zwei Megabyte Wenn Sie es direkt auf diese Weise hochladen, ist das Bild zu groß. Wenn der Benutzer mobile Daten verwendet, ist es offensichtlich keine gute Idee, das Bild vollständig hochzuladen.

Derzeit wurden verschiedene neue APIs von HTML5 besser auf dem mobilen Webkit implementiert. Laut caniuse wurden die in dieser Demo verwendeten FileReader-, Blob- und Formdata-Objekte in den meisten Browsern für mobile Geräte (Safari 6.0+, Android 3.0+) implementiert, sodass das Komprimieren von Bildern direkt im Frontend zu einem wesentlichen Bestandteil geworden ist Funktionen zum Hochladen von Bildern auf mobile Geräte.

Beim Komprimieren und Hochladen von Bildern auf dem mobilen Endgerät werden hauptsächlich die drei h5-APIs Filereader, Canvas und Formdata verwendet. Die Logik ist nicht schwierig. Der gesamte Prozess ist:

(1) Wenn der Benutzer die Eingabedatei zum Hochladen eines Bildes verwendet, verwenden Sie den Dateireader, um die vom Benutzer hochgeladenen Bilddaten zu lesen (Base64-Format)

(2) Bestanden Fügen Sie die Bilddaten in das img-Objekt ein, zeichnen Sie dann img auf die Leinwand und rufen Sie dann canvas.toDataURL auf, um das Bild zu komprimieren

(3) Erhalten Sie die komprimierten Bilddaten im Base64-Format, konvertieren Sie sie in eine Binärdatei und fügen Sie sie in formdata ein. und übermitteln Sie dann die Formulardaten über XmlHttpRequest.

In diesen drei Schritten sind die Bildkomprimierung und das Hochladen abgeschlossen.

Es klingt einfach, aber tatsächlich gibt es dennoch einige Fallstricke. Verwenden Sie als Nächstes den Code zur direkten Analyse:

[1] Bilddaten abrufen

Rufen Sie zunächst die Bilddaten ab, dh hören Sie sich das Änderungsereignis an Geben Sie die Datei ein und erhalten Sie sie. Konvertieren Sie für die hochgeladenen Dateiobjektdateien die arrayähnlichen Dateien in ein Array und führen Sie dann eine forEach-Durchquerung durch.

Bestimmen Sie dann den Dateityp. Wenn es sich nicht um ein Bild handelt, wird es nicht verarbeitet. Wenn es sich um ein Bild handelt, instanziieren Sie einen Dateileser, lesen Sie die hochgeladenen Dateidaten im Base64-Format und bestimmen Sie die Datenlänge. Wenn das Bild größer als 200 KB ist, rufen Sie die Komprimierungsmethode auf, um es zu komprimieren, andernfalls rufen Sie die Upload-Methode zum Hochladen auf.

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);
   })
  };
Nach dem Login kopieren

【2】Komprimieren Sie das Bild

Nachdem Sie die Erfassung der Bilddaten oben abgeschlossen haben, können Sie die Komprimierung durchführen Bildkomprimierungsmethode. Beim Komprimieren von Bildern ist es nicht erforderlich, das Bild direkt auf die Leinwand zu zeichnen und dann toDataURL aufzurufen.

In IOS gibt es zwei Einschränkungen für das Zeichnen von Bildern auf Leinwand:

Die erste ist die Größe des Bildes. Wenn die Größe des Bildes zwei Millionen Pixel überschreitet, kann das Bild nicht gezeichnet werden Auf der Leinwand wird beim Aufruf von drawImage kein Fehler gemeldet. Wenn Sie jedoch toDataURL zum Abrufen von Bilddaten verwenden, erhalten Sie leere Bilddaten.

Darüber hinaus ist die Größe der Leinwand begrenzt. Wenn die Größe der Leinwand größer als etwa fünf Millionen Pixel (also das Produkt aus Breite und Höhe) ist, kann nicht nur das Bild, sondern auch andere nicht gezeichnet werden Dinge können nicht gezeichnet werden.

Um die erste Einschränkung zu umgehen, besteht die Lösung darin, Kacheln zu zeichnen. Beim Kachelzeichnen wird das Bild in mehrere Teile geteilt und auf die Leinwand gezeichnet. Die Methode in meinem Code besteht darin, das Bild in 1 Million Pixel zu unterteilen und es dann auf die Leinwand zu zeichnen.

Um die zweite Einschränkung zu umgehen, besteht meine Lösung darin, die Breite und Höhe des Bildes entsprechend zu komprimieren. Aus Sicherheitsgründen liegt die Obergrenze in meinem Code bei vier Millionen Pixeln Vier Millionen Pixel. Komprimieren Sie es einfach auf weniger als 4 Millionen Pixel. Ein 4-Megapixel-Bild mit einer Breite und Höhe von 2000 x 2000 sollte ausreichen.

Auf diese Weise werden die beiden Einschränkungen bei IOS gelöst.

Zusätzlich zu den oben genannten Einschränkungen gibt es zwei Fallstricke: Erstens kann die toDataURL von Canvas nur JPG komprimieren Das heißt, es kann einheitlich verwendet werden: canvas.toDataURL("image/jpeg", 0.1), der Typ ist einheitlich auf jpeg eingestellt und das Komprimierungsverhältnis wird von selbst gesteuert.

Das andere ist, dass, wenn Sie PNG in JPG konvertieren und es auf die Leinwand zeichnen und die Leinwand einen transparenten Bereich hat, der transparente Bereich schwarz wird, wenn Sie ihn in JPG konvertieren, da die transparenten Pixel der Leinwand standardmäßig verwendet werden in rgba ( 0,0,0,0), also wird es bei der Konvertierung in jpg zu rgba(0,0,0,1), d. h. der transparente Hintergrund wird schwarz. Die Lösung besteht darin, vor dem Zeichnen einen weißen Hintergrund auf die Leinwand zu legen.

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;
 }
Nach dem Login kopieren

【3】Bild-Upload

Nach Abschluss der Bildkomprimierung können Sie es in die Formulardaten einfügen und Laden Sie es hoch, konvertieren Sie zuerst die Base64-Daten in eine Zeichenfolge, instanziieren Sie dann einen ArrayBuffer, übergeben Sie die Zeichenfolge dann im Format einer 8-Bit-Ganzzahl an den ArrayBuffer und konvertieren Sie dann den 8-Bit-Ganzzahl-ArrayBuffer mit dem BlobBuilder- oder Blob-Objekt in ein binäres Objekt blob, hängen Sie dann das Blob-Objekt an formdata an und senden Sie es dann über Ajax an den Hintergrund.

XmlHttpRequest2 kann nicht nur große Datenmengen senden, sondern verfügt auch über zusätzliche APIs, z. B. zum Abrufen des Sendefortschritts. Ich habe es auch einfach in meinen Code implementiert.

// 图片上传,将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);
 }
Nach dem Login kopieren

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

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

相关推荐:

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

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

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

Das obige ist der detaillierte Inhalt vonDas mobile Endgerät verwendet H5, um die Funktion zum Komprimieren von Bild-Uploads zu implementieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!